最近在學(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)于類和繼承的基本語法就說這么多了,歡迎大家批評指正!