Kotlin 中的继承

继承

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()
    }
}

你可能感兴趣的:(Kotlin)