继承

回到目录
项目源码 kotlin-class 项目


Kotlin 中所有类都有一个共同的父类 Any. 如果没有显式声明父类, 都会隐式默认继承它

class Example // Implicitly inherits from Any

Any 并不是 java.lang.Object. 它除了 equals(), hashCode() 与 toString()
外没有任何成员

要显示声明父类, 可以把父类的构造函数放在类头的冒号后面:

open class BaseA

class DerivedA: BaseA()

Kotlin 中的类默认都是不被基层的, 相当于 java 中的 final class. 如果想要被继承,
可以在前面使用 open 关键字"打开封印".

也可以用次构造函数:

open class BaseB(val a: Int, val b: Int?, val c: Int) {
    constructor(a: Int, c: Int): this(a, null, c)
}

//  使用父类的用次构造函数也是可以的
class DerivedB(a: Int, b: Int?, c: Int, val d: Int, val e: Int): BaseB(a, c)
/*
会生成这样的构造函数:
   public DerivedB(int a, @Nullable Integer b, int c, int d, int e) {
      super(a, c);
      this.d = d;
      this.e = e;
   }
 */

派生类没有主构造函数, 使用次构造函数继承的情况:

// 如果派生类没有主构造函数
class DerivedBB: BaseB {
    // 因为属性必须初始化, 所以写上 getter
    // 没有必要写 setter, 会自动生成
    var d: Int
        get() = field
    var e: Int
        get() = field
    // 使用次构造函数继承父类, 得用 super 关键字
    constructor(a: Int, b: Int?, c:Int, d: Int, e:Int): super(a, b, c) {
        this.d = d
        this.e = e
    }
    constructor(a: Int, c: Int, d: Int, e: Int): super(a, c) {
        this.d = d
        this.e = e
    }

重写方法(overriding)

方法的重写也需要再父类中"打开封印", 因为方法也是默认 public final 的.

open class BaseC {
    open fun funC() {
        println("funC")
    }
}
class DerivedC: BaseC() {
    override fun funC() {
//        super.funC()
        println("重写后的 funC")
    }
}

fun main(args: Array) {
    val derivedC = DerivedC()
    derivedC.funC()
}

标记为 override 后, 改方法本身就变成 open 的了, 可以用 final 再次禁止重写.

重写属性

跟重写方法一样, 重写属性也需要 open 关键字然后再 override:

open class BaseD {
    open var d: Int = 0
    // 这个是没有 backing field 的
    open val dd get() = true
}

class DerivedD: BaseD() {
    override var d: Int = 1
    override var dd = false
}

调用父类方法及属性

可以使用 super 调用父类的方法和属性的实现.

open class BaseE {
    open fun funE() { println("BaseE.funE()") }
    open val e get() = 1
}

class DerivedE: BaseE() {
    override fun funE() {
        super.funE()
        println("DerivedE.funE()")
    }
    override val e get() = super.e + 1
}

内部类想调用外部内的父类方法属性可以用 super@Outer 语法实现:

class DerivedE: BaseE() {
    override fun funE() {
        super.funE()
        println("DerivedE.funE()")
    }
    override val e get() = super.e + 1
    inner class InnerE {
        fun f() {
            [email protected]()
            println([email protected])
        }
    }
}

继承规则

如果一个类继承了多个直接超类(父类和接口), 并且这些父类中有同名的成员(属性或方法), 同名成员必须
重写实现; 需要调用不同父类的同名成员, 使用 super<父类> 来区别.

open class BaseF {
    open fun f() {
        println("BaseF.f()")
    }
    open val f get() = "BaseF.f"
}
interface IBaseG {
    // 接口中的方法和属性默认都是 open 的
    // 接口可以有实现代码
    fun f() {
        println("IBaseG.f()")
    }
    val f get() = "IBaseG.f"
}

class DerivedFG: BaseF(), IBaseG {
    override fun f() {
        super.f()
        super.f()
    }
    override val f get() = super.f + super.f
}

抽象类

一个类中只要有一个抽象方法(abstract 标记的, 没有实现代码的方法), 那么这个类就
是抽象类, 也必须用 abstract 标记.

可以用抽象类的抽象方法去继承重写非抽象类的方法:

open class BaseH {
    open fun f() {}
}

abstract class DerivedH : BaseH() {
    override abstract fun f()
}

伴生对象

Kotlin 中没有 static 静态方法, 大部分情况下都推荐使用包级函数来代替.

还有一种情况, 如果不用类实例对象来调用, 但又需要访问类内部(比如工厂方法), 那就
需要在类中写一个"对象声明"(object declaration), 准确的说应该是需要声明一个"伴生
对象"(companion object).

class MyClass {
    // 可以省略伴生类的类名
    companion object {
        fun create(): MyClass = MyClass()
    }
}

然后可以这样去用(很像 static 方法):

val instance = MyClass.create()

回到目录

你可能感兴趣的:(继承)