Kotlin 中所有類都有一個共同的父類 Any. 如果沒有顯式聲明父類, 都會隱式默認繼承它
class Example // Implicitly inherits from Any
Any
并不是java.lang.Object
. 它除了 equals(), hashCode() 與 toString()
外沒有任何成員
要顯示聲明父類, 可以把父類的構(gòu)造函數(shù)放在類頭的冒號后面:
open class BaseA
class DerivedA: BaseA()
Kotlin 中的類默認都是不被基層的, 相當于 java 中的 final class
. 如果想要被繼承,
可以在前面使用 open
關(guān)鍵字"打開封印".
也可以用次構(gòu)造函數(shù):
open class BaseB(val a: Int, val b: Int?, val c: Int) {
constructor(a: Int, c: Int): this(a, null, c)
}
// 使用父類的用次構(gòu)造函數(shù)也是可以的
class DerivedB(a: Int, b: Int?, c: Int, val d: Int, val e: Int): BaseB(a, c)
/*
會生成這樣的構(gòu)造函數(shù):
public DerivedB(int a, @Nullable Integer b, int c, int d, int e) {
super(a, c);
this.d = d;
this.e = e;
}
*/
派生類沒有主構(gòu)造函數(shù), 使用次構(gòu)造函數(shù)繼承的情況:
// 如果派生類沒有主構(gòu)造函數(shù)
class DerivedBB: BaseB {
// 因為屬性必須初始化, 所以寫上 getter
// 沒有必要寫 setter, 會自動生成
var d: Int
get() = field
var e: Int
get() = field
// 使用次構(gòu)造函數(shù)繼承父類, 得用 super 關(guān)鍵字
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<String>) {
val derivedC = DerivedC()
derivedC.funC()
}
標記為 override
后, 改方法本身就變成 open
的了, 可以用 final
再次禁止重寫.
重寫屬性
跟重寫方法一樣, 重寫屬性也需要 open
關(guān)鍵字然后再 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
}
調(diào)用父類方法及屬性
可以使用 super
調(diào)用父類的方法和屬性的實現(xiàn).
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
}
內(nèi)部類想調(diào)用外部內(nèi)的父類方法屬性可以用 super@Outer
語法實現(xiàn):
class DerivedE: BaseE() {
override fun funE() {
super.funE()
println("DerivedE.funE()")
}
override val e get() = super.e + 1
inner class InnerE {
fun f() {
super@DerivedE.funE()
println(super@DerivedE.e)
}
}
}
繼承規(guī)則
如果一個類繼承了多個直接超類(父類和接口), 并且這些父類中有同名的成員(屬性或方法), 同名成員必須
重寫實現(xiàn); 需要調(diào)用不同父類的同名成員, 使用 super<父類>
來區(qū)別.
open class BaseF {
open fun f() {
println("BaseF.f()")
}
open val f get() = "BaseF.f"
}
interface IBaseG {
// 接口中的方法和屬性默認都是 open 的
// 接口可以有實現(xiàn)代碼
fun f() {
println("IBaseG.f()")
}
val f get() = "IBaseG.f"
}
class DerivedFG: BaseF(), IBaseG {
override fun f() {
super<BaseF>.f()
super<IBaseG>.f()
}
override val f get() = super<BaseF>.f + super<IBaseG>.f
}
抽象類
一個類中只要有一個抽象方法(abstract
標記的, 沒有實現(xiàn)代碼的方法), 那么這個類就
是抽象類, 也必須用 abstract
標記.
可以用抽象類的抽象方法去繼承重寫非抽象類的方法:
open class BaseH {
open fun f() {}
}
abstract class DerivedH : BaseH() {
override abstract fun f()
}
伴生對象
Kotlin 中沒有 static
靜態(tài)方法, 大部分情況下都推薦使用包級函數(shù)來代替.
還有一種情況, 如果不用類實例對象來調(diào)用, 但又需要訪問類內(nèi)部(比如工廠方法), 那就
需要在類中寫一個"對象聲明"(object declaration), 準確的說應(yīng)該是需要聲明一個"伴生
對象"(companion object).
class MyClass {
// 可以省略伴生類的類名
companion object {
fun create(): MyClass = MyClass()
}
}
然后可以這樣去用(很像 static
方法):
val instance = MyClass.create()