Java入坑Kotlin系列之類與繼承

最近在學(xué)習(xí)Kotlin的過程中發(fā)現(xiàn)之前學(xué)習(xí)過的知識如果沒有在實(shí)際項目中去用的話,過了一段時間后就會慢慢遺忘,想了想可能還是因為印象不夠深刻,所以還是決定用寫作的方式讓自己加深對知識點(diǎn)的理解,希望在加深印象的同時也能留下自己學(xué)習(xí)的記錄,哈哈!話不多說,就先從Kotlin中的類開始說起吧。

  • 類的定義

和Java一樣,在Kotlin中定義一個類同樣也是使用關(guān)鍵字class來進(jìn)行聲明,例如定義一個Person類如下:

class Person {}

實(shí)際上Java中定義一個類也是同樣的方式,但是與Java不同的是在Kotlin中如果類沒有主體,可以省略花括號,如下所示:

class Person

在Java中這種寫法可就報錯了喲!

  • 構(gòu)造函數(shù)

在Kotlin中有兩種2構(gòu)造函數(shù):主構(gòu)造函數(shù)、次構(gòu)造函數(shù)

  • 主構(gòu)造函數(shù)

主構(gòu)造函數(shù)是類頭的一部分,它跟在類名后,定義如下:

class Person constructor(name: String)

如果主構(gòu)造函數(shù)沒有任何注解或者可見性修飾符,可以省略這個constructor關(guān)鍵字,定義如下:

class Person(name: String)

說到這里之前用Java的童鞋可能會有點(diǎn)疑問,在Java中我可以在構(gòu)造函數(shù)中進(jìn)行類的一些初始化工作,那在Kotlin中這些操作要放在哪里呢?在Kotlin語法中主構(gòu)造函數(shù)不能包含任何的代碼,初始化的代碼可以放到以init關(guān)鍵字作為前綴的初始化塊中,屬性可以在屬性初始化器中進(jìn)行賦值,例如:

class Person(name: String) {

  //這里是屬性初始化器進(jìn)行賦值
  val nameDesc = "name:$name"

  //這里是init初始化塊
  init {
    println("name is $name")
  }
}

事實(shí)上定義一個有屬性的類還有更加簡潔的寫法,直接在主構(gòu)造函數(shù)中為參數(shù)添加一個var或val進(jìn)行修飾,那這個參數(shù)同時就是這個類的屬性,如下所示:

class Person(val name: String, val age: Int)

這種寫法等價于下面的定義:

class Person {
  val name: String
  val age: Int
}

如果構(gòu)造函數(shù)有注解或可見性修飾符,這個constructor關(guān)鍵字是必需的,并且這些修飾符在它前面:

class Person public @Inject constructor(name: String, age: Int)
  • 次構(gòu)造函數(shù)

除了主構(gòu)造函數(shù),類也可以在類體內(nèi)使用constructor來聲明次構(gòu)造函數(shù),從表面上看次構(gòu)造函數(shù)和Java中的構(gòu)造函數(shù)很相似,先看一下定義:

class Person {
  constructor(name: String) {
    //TODO
  }
}

如果類有一個主構(gòu)造函數(shù),每個次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù), 可以直接委托或者通過別的次構(gòu)造函數(shù)間接委托。委托到同一個類的另一個構(gòu)造函數(shù)用this關(guān)鍵字即可:

class Person(val name: String) {
  constructor(name: String, age: Int): this(name) {
    //TODO
  }
}
  • 創(chuàng)建類的實(shí)例

在Kotlin中創(chuàng)建一個類的示例很簡單,直接向函數(shù)調(diào)用一樣即可,也不需要像Java中使用new關(guān)鍵字,示例如下:

val p = Person("Kotlin")
val p2 = Person("Kotlin", 3)

繼承

我們知道在Java中所有的類都有一個共同的超類Object,而在 Kotlin 中同樣也存在這種語法,所有類都有一個共同的超類Any,Any有三個方法:equals()、 hashCode()、 toString()。由于Kotlin的類都是繼承自Any,因此所有Kotlin類也都定義了這些方法。現(xiàn)在我們來說一說繼承,默認(rèn)情況下,Kotlin類是final的,它們不能被繼承。 要使一個類可被繼承,需要使用open關(guān)鍵字進(jìn)行標(biāo)記。定義如下所示:

open class Person(name: String)

現(xiàn)在這個Person類是可以被繼承的,Kotlin語法定義中繼承使用冒號(:),現(xiàn)在定義一個Person類的子類:

class Teacher(name: String, job: String) : Person(name)

同樣的Kotlin對于可覆蓋的成員也需要顯式修飾符open,這樣才能被子類覆蓋,覆蓋的屬性或方法必須加上override修飾符,如下所示:

open class Person(name: String) {
  val name: String = name
  open val money: Int = 0
  open fun work() {}
  fun eat() {}
}

class Teacher(name: String) : Person(name) {
  override val money: Int = 100
  override fun work() {}
  override val name: String = name //該屬性不能被覆蓋,編譯器報錯
  override fun eat() {} //該方法不能被覆蓋,編譯器報錯
}

如果函數(shù)沒有標(biāo)注open如Teacher.eat(),那么子類中不允許定義相同簽名的函數(shù),不論加不加override。另外,將open修飾符添加到final類(即沒有open的類)的成員上是不起作用的。標(biāo)記為override的成員本身是開放的,也就是說,它可以在子類中覆蓋。如果想禁止再次覆蓋,需要使用final關(guān)鍵字:

class Teacher(name: String) : Person(name) {
  final override val money: Int = 100
  final override fun work() {}
}

抽象類

類以及其中的某些成員可以聲明為abstract,抽象成員在本類中可以不用實(shí)現(xiàn)。 而且我們并不需要用open標(biāo)注一個抽象類或者函數(shù),因為抽象類或函數(shù)本身就是想讓其他類繼承或?qū)崿F(xiàn)的。抽象類定義示例如下:

abstract class Person {
  abstract val money: Int
  abstract fun work()
}

class Teacher : Person() {
    override val money: Int = 100
    override fun work() {
      println("My work is teaching")
    }
}

好了,關(guān)于類和繼承的基本語法就說這么多了,歡迎大家批評指正!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容