Kotlin 修煉手冊(5)繼承與接口

前言

這篇的內容仍是和類有關,介紹 Kotlin 中繼承和接口。html

繼承

Kotlin 中全部類都繼承自 Any 類,是全部類的超類,相似於 Java 中的 Objectbash

Any 默認提供三個函數:ide

equals()
hashCode()
toString()
複製代碼

默認的類都是不可被繼承的,相似於 Java 中的 final 類。函數

要讓類能夠被繼承,須要加 open 關鍵字修飾。post

open class Base{}
複製代碼

構造函數

若是子類有主構造函數,則基類必須在主構造函數中當即初始化。ui

open class Person(var name: String, var age: Int) {
    var mName = name
    var mAge = age
}

class Student(name: String, age: Int, var no: String, var score: Int) : Person(name, age) {
    var mNo = no
    var mScore = score
}

fun main(args: Array<String>) {
    val s = Student("Owen",23, "12138",100)
    println("學生名字:${s.mName}")
    println("學生年齡:${s.mAge}")
    println("學生學號:${s.mNo}")
    println("學生成績:${s.mScore}")
}

// 運行結果
學生名字:Owen
學生年齡:23
學生學號:12138
學生成績:100
複製代碼

若是子類沒有主構造函數,則必須在每個次級構造函數中須要使用 super 關鍵字調用基類的構造函數,或者使用 this 關鍵字調用子類另外一個構造函數,初始化基類時,能夠調用基類不一樣的構造函數。this

open class Person(name: String) {
    var mName = name
    var mAge: Int = 0

    init {
        println("-----這是基類的主構造函數----")
    }

    constructor(name: String, age: Int) : this(name) {
        mAge = age
        println("-----這是基類的次級構造函數----")
    }
}

class Student : Person {
    var mNo: String = ""
    var mScore: Int = 0

    constructor(name: String, age: Int, no: String) : super(name, age) {
        mNo = no
        println("-----這是子類的三個參數的次級構造函數----")
    }

    constructor(name: String, age: Int, no: String, score: Int) : this(name, age, no) {
        mScore = score
        println("-----這是子類的四個參數的次級構造函數----")
    }
}

fun main(args: Array<String>) {
    val s = Student("Owen", 23, "70", 100)
    println("學生名字:${s.mName}")
    println("學生年齡:${s.mAge}")
    println("學生學號:${s.mNo}")
    println("學生成績:${s.mScore}")
}
//運行結果
-----這是基類的主構造函數----
-----這是基類的次級構造函數----
-----這是子類的三個參數的次級構造函數----
-----這是子類的四個參數的次級構造函數----
學生名字:Owen
學生年齡:23
學生學號:70
學生成績:100
複製代碼

函數重寫

在基類中,函數默認爲 final 修飾,不可被重寫。若是容許子類重寫,須要手動添加 open 關鍵字進行修飾,子類重寫函數使用 override 關鍵字。spa

open class Person {
    open fun study() {
        println("我畢業了")
    }
}
class StudentA : Person() {
    override fun study() {
        println("我在讀大學")
    }
}
fun main() {
    val s = Student()
    s.study() 
}
//輸出結果
我在讀大學
複製代碼

子類能夠用一個函數重寫父類和接口中的多個同名函數。若是要調用父類或接口的函數實現,須要用 super 關鍵字來顯式調用。code

open class A {
    open fun f() {
        println("A:f")
    }
}

interface B {
    fun f() {
        println("B:f")
    }
}

class C : A(), B {
    override fun f() {
        super<A>.f()  //調用父類A中f()的實現,也能夠選擇不調用
        super<B>.f()  //調用接口B中f()的實現,也能夠選擇不調用
        println("C:f")
    }
}

fun main() {
    val c = C()
    c.f()
}

//運行結果
A:f
B:f
C:f
複製代碼

屬性重寫

Kotlin 中支持對屬性進行重寫,屬性重寫用 override 關鍵字。基類中被重寫的屬性須要用 open 關鍵字修飾,不能爲 private。htm

open class A {
    open var property: String = "a"
}

class B : A() {
    override var property: String = "b"
}

fun main() {
    val b = B()
    println(b.property)
}
//運行結果
b
複製代碼

能夠使用一個 var 屬性重寫一個 val,可是反過來不行(可變比不可變的範圍更大)。val 屬性自己定義了 getter 方法,重寫爲 var 屬性會在子類中額外聲明一個 setter 方法。(機制相似於子類不能將 public 的方法重寫爲 private 的,範圍不能縮小,只能變大)

能夠在子類的主構造函數中使用 override 關鍵字做爲屬性聲明的一部分。

interface Foo{
    val count :Int
}

class Bar1(override val count: Int):Foo{

}

class Bar2:Foo{
    override val count: Int = 0
        get() = field
}

fun main(){
    val bar1 = Bar1(4)
    println(bar1.count)
    val bar2 = Bar2()
    println(bar2.count)
}
複製代碼

子類繼承父類時,不能有跟父類同名的變量,除非父類中該變量爲 private,或者父類中該變量爲 open 而且子類用 override 關鍵字重寫。

Kotlin 接口

Kotlin 接口與 Java8 相似,使用 interface 關鍵字,容許方法有默認實現。

interface MyInterface {
    fun b()   //未實現
    fun f() { //已實現
        println("MyInterface:f")
    }
}
複製代碼

一個類能夠實現一個或多個接口。多個接口中有同名方法時,和前面提到的類和接口中又同名方法的處理是同樣的。

接口中的屬性只能是抽象的,不容許 初始化值,接口不會保存屬性值,實現接口時,必須 重寫屬性。

interface MyInterface {
    var name :String // 屬性,抽象的
    fun b()
    fun f() {
        println("MyInterface:f")
    }
}

class Child : MyInterface {
    override var name: String = "owen"
    override fun b() {
        println("Child:b")
    }
}

fun main() {
    val c = Child()
    c.b()
    c.f()
    println(c.name)
}
複製代碼

參考資料

Kotlin 繼承

Kotlin 接口

Kotlin——中級篇(四):繼承類詳解

相關文章
相關標籤/搜索