Kotlin的类和接口和Java还是有一些区别的。例如:接口可以包含属性声明。与Java不同,Kotlin的声明默认是final和public的。此外,嵌套的类默认并不是内部类:它们并没有包含其外部类的隐式引用。
对于构造方法来说,简短的主构造方法语法在大多数情况下都工作得很好,但是依然有完整的语法可以让你声明带有重要初始化逻辑的构造方法。对于属性来说也是一样的:简洁的语法非常好用,但是还是可以方便地定义自己的访问器实现。
Kotlin编辑器能够生成有用的方法来避免冗余。将一个类声明为data类可以让编辑器生成若干标准方法。同样可以避免写委托方法,因为委托模式是Kotlin原生支持的。
4.1类的继承结构
Kotlin的可见性和访问修饰符与Java的类似但还是有一些不一样的默认行为。还会学到新的用于限制一个类可能存在的子类的sealed修饰符。
4.1.1Kotlin中的接口
Kotlin中的接口与Java8中的相似:它们可以包含抽象方法的定义以及非抽象方法的实现,但它们不能包含任何状态。
使用interface来声明一个Kotlin的接口:
interface Clickable {
fun click()
}
这声明了一个拥有名为click的单抽象方法的接口。所有实现这个接口的非抽象类都需要提供这个方法的一个实现,接下来就是该如何实现这个接口:
class Button : Clickable {
override fun click() = println("我被点击了")
}
>>>Button().click()
>我被点击了
Kotlin在类名后面使用冒号来代替了Java中的extends和implements关键字。和Java一样,一个类可以实现多个接口,但是只能继承一个类。
与Java中的@Override注解类似,override修饰符用来标注被重写的父类或者接口的方法和属性。与Java不同的是,在kotlin中使用override修饰符是强制要求的。这会避免先写出实现方法再添加抽象方法造成的意外重写。除非显式地将这个方法标注为override或者重命名它,否则代码将不能编译。
接口的方法可以有一个默认的实现。与Java8不同的是,Java8中需要在这样的实现上标注default关键字,对于这样的方法,Kotlin没有特殊的注解,只需要提供一个方法体:
interface Clickable {
fun click()
fun showOff() = println("我能被点击")
}
如果你实现了这个接口,你需要为click提供一个实现。可以重新定义showOff方法,也可以直接省略它。
现在假设存在同样定义了一个showOff方法并且有如下实现的另一个接口:
interface Focusable {
fun setFocus(b: Boolean) = println("I ${if (b) "got" else "lose"} focus.")
fun showOff() = println("我能被点击")
}
如果需要在类中实现这两个函数会发生什么?它们没一个都包含了带默认实现的showOff方法,将会使用哪一个实现?实际上任何一个都不会使用,如果没有显式地实现showOff,还会报个错。Kotlin编译器会强制要求你提供自己的实现。
调用继承自接口方法的实现:
class Button : Clickable, Focusable {
override fun click() = println("我被点击了")
override fun showOff() {
super<Clickable>.showOff()
super<Focusable>.showOff()
}
}
现在Button类实现了两个接口。通过调用继承的两个父类型中的实现来实现showOff。要调用一个继承的实现,可以使用Java中相同的关键字super。在Java中可以把基类的名字放在super关键字的前面,就像Clickable.spuer.showOff()
这样,在Kotlin需要把基类的名字放在尖括号中:super<Clickable>.showOff()
。
如果只需要调用一个继承的实现,可以这样:
override fun showOff() = super<Clickable>.showOff()
可以创建一个这个类的实例来验证所有继承的方法都可被调用到:
fun main(args: Array<String>) {
val button = Button()
button.showOff()
button.setFocus(true)
button.click()
}
setFocus的实现是在Focusable接口中声明的并且被Button类自动继承了。