一. 接口
1、 ) 接口的定义
- ) 使用关键字 interface 来定义接口
- )Kotlin 接口的方式可以是抽象的,也可以提供默认的实现(即方法体是可选的)
- )Kotlin接口的属性必须声明为抽象(不能初始化)或提供访问器实现。并且在接口中声明的属性不能有幕后字段(backing field),因此接口中声明的访问器不能引用field,var声明的可变变量的访问器依赖幕后字段。所以var属性只能是抽象的,val 属性 可以提供getter访问器
完整示例:
interface MyInterface {
val prop: Int // 抽象的
val parameterA:Int=1 //会报错,编译器提示不能在接口中初始化属性
val propertyWithImplementation: String //提供访问器
get() = "foo"
var parameterA : Int
get() = 1
//报错,编译器提示不能使用幕后字段。因为 var 声明的可变变量的访问器依赖幕后字段field,所以无论getter和setter访问器都无法使用
fun bar() //抽象的方法,没有方法体
fun foo() {
// 可选的方法体
}
}
2、)接口的实现
- )Java中使用是implements关键字实现接口,kotlin使用
冒号:实现接口。 - )一个类可以实现一个或多个接口。
- )实现接口需要实现抽象的接口成员。
示例:
class Child : MyInterface {
override fun bar() {
// 方法体
}
}
3、)接口的继承
接口的继承基本和Java相同
一个接口可以从其他接口派生,从而既提供父接口成员的实现也可以继续声明新的函数与属性。实现这样接口只需定义所缺少成员实现。
示例:
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// 不必实现“name”
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
4、)接口的冲突问题
当我们的实现类,实现了多个接口时,并且这些接口中有相同名字的方法时,如果我们想调用父接口的这些方法,编译器就不能区分我们想调用哪个。所以可以用super<接口名>.方法名来区分。
示例:
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
5、)函数式(SAM)接口
- )只有一个抽象方法的接口称为函数式接口或 SAM(单一抽象方法)接口。函数式接口可以有多个非抽象成员,但只能有一个抽象成员。
- )使用用 fun 修饰符在 Kotlin 中声明一个函数式接口。
示例:
fun interface KRunnable {
fun invoke()
}
对于函数式接口,可以通过 lambda 表达式实现 SAM 转换,从而使代码更简洁、更有可读性。具体可以查看 lambda 表达式的相关知识。
二、抽象类
kotlin的抽象类和Java基本相同。
在Java的设计模式中,有一种设计模式叫模板设计模式,其定义为:
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
就是完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。
我们在实际开发中,一般会写一个基类,封装常用方法、以及处理一些共有的逻辑,但是程序逻辑是根据每个子类不同的功能实现不同的代码。这个基类一般都是一个抽象类。
所以抽象类,可以理解为类定义了一个模板。所有的子类都是根据这个模板是填充自己的代码。
- )使用abstract关键字声明一个抽象类
- )抽象类除了可以有其自己的属性、构造函数、方法等组成部分,还包含抽象成员(抽象函数以及抽象属性),抽象成员也使用abstract关键字声明,并且抽象成员只有定义,没有实现。
- )抽象类不能直接被实例化
- )抽象类的子类必须全部重写带abstract修饰的属性和方法(抽象成员)
- )抽象类是为其子类定义了一个模板。不同是类实现不同的功能
一个示例:
abstract class Person {
val tag="人" //普通类的属性
fun getUserInfo(){ //普通类的方法
}
abstract var userWork : String // 抽象属性
abstract fun doWork() // 抽象方法
}
class Teacher : Person() {
override var userWork : String
get() = "老师"
set(value) {}
override fun doWork() {
}
}
- )抽象类可以继承自一个继承类,即抽象类可以作为子类。不过,抽象类建议不用open修饰符修饰,因为可以覆写抽象类的父类的函数。
open class Polygon {
open fun draw() {}
}
abstract class Rectangle : Polygon() {
abstract override fun draw()
}