Kotlin 中所有的类都有一个共同的超类 Any,对于没有超类型声明的类默认超类是 Any。看看它的源码:
public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
很简单,就三个方法。当我们要显示的声明一个超类的时候,我们把超类放在类型的冒号之后:
open class Base(p: Int)
class Derived(p: Int) : Base(p)
open 关键字表示这个类允许其他类从这个类继承,与 Java 中的 final 正好相反。默认情况下,Kotlin 中所有的类都是 final。(要么为继承而设计,并提供文档说明,要么就禁止继承)。如果子类有一个主构造函数,那么其基类必须用基类的主构造函数就地初始化。如果子类没有主构造函数,那么每个次构造函数必须用 super 关键字初始化其类型,不同的次构造函数可以调用基类不同的构造函数:
class MyView: View {
constructor(ctx: Context) : supter(ctx)
constructor(ctx: Context,attrs: AttributeSet) : super(ctx,attrs)
}
Kotlin 需要显示标注可覆盖的成员和覆盖后的成员:
open class Base {
open fun v(){}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
子类的方法必须用 override 标注,否则,编译不过,子类中不允许定义相同签名的函数;基类的方法必须用 open 标注。用 override 标记的成员本身是开放的,就是说,可以在子类中覆盖。如果想禁止覆盖,需要使用 final 关键字:
open class AnotherDerived(): Base() {
final override fun v() {}
}
覆盖属性和覆盖方法类似:在基类中以 open 声明,然后在子类中以 override 重新声明。我们可以用一个 var 覆盖一个 val 属性,但是不能用 val 属性覆盖 var 属性。因为一个 val 属性本质上声明了一个 getter 方法,将其覆盖为 var 只是在子类中额外声明一个 setter 方法。
open class Base {
open var x : Int = 9
open fun v(){}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
override var x : Int = 2
}
在构造派生类的新实例的过程中,第一步完成其基类的初始化(在之前只有对基类构造函数参数的求值),因此发生在派生类的初始化逻辑运行之前。
fun main(args: Array) {
var derived = Derived("Hello" ,"World")
}
open class Base(val name: String) {
init { println("Initializing Base") }
open val size: Int =
name.length.also { println("Initializing size in Base: $it") }
}
class Derived(name: String,val lastName: String ) :
Base(name.capitalize().also { println("Argument for Base: $it") }) {
init { println("Initializing Derived") }
override val size: Int =
(super.size + lastName.length).also { println("Initializing size in Derived: $it") }
}
Log输出:
Argument for Base: Hello
Initializing Base
Initializing size in Base: 5
Initializing Derived
Initializing size in Derived: 10
这意味着,基类构造函数执行时,派生类中声明和覆盖的属性都还没有初始化。如果在基类初始化逻辑中(直接或间接通过另一个覆盖的 open 成员的实现间接)使用了任何一个这种属性,那么都可能导致不正确的行为或运行时故障。设计一个基类时,应该避免在构造函数,属性初始化器以及 init 代码块中使用 open 成员。
子类中的代码可以使用 super 关键字调用其超类的函数与属性访问器的实现;在一个内部类中访问外部类的超类,可以通过由外部类名限定的 super 关键字来实现:super@Outer:
open class Foo {
open fun f() {
println("Foo.f()")
}
open val x: Int get() = 1
}
class Bar : Foo() {
override fun f() {
super.f()
println("Bar.f()")
}
override val x: Int get() = super.x + 1
inner class Baz {
fun g() {
[email protected]() // 调用 Foo 实现的 f()
println([email protected]) // 使用 foo 实现的 x 的 getter
}
}
}
如果一个类从它的直接超类继承相同成员的多个实现,它必须覆盖这个成员比提供自己的实现。为了表示采用从哪个超类继承的实现,我们使用尖括号中超类型名限定的 super:
open class A {
open fun f() {
println("A")
}
fun a() {
println("a")
}
}
interface B {
fun f(){
println("B")
}
fun b() {
println("b")
}
}
class C() : A(),B {
override fun f() {
super.f() // 调用 A.f()
super.f() // 调用 B.f()
}
}