kotlin類和對(duì)象—>類與繼承
1.類的定義,kotlin中依舊使用關(guān)鍵字class聲明類,類聲明由類名、類頭(指定其類型參數(shù)、主構(gòu)造函數(shù)等)以及由花括號(hào)包圍的類體構(gòu)成。類頭與類體都是 可選的;如果一個(gè)類沒有類體,可以省略花括號(hào)。
//1.簡(jiǎn)單定義 class Invoice { /*......*/ } //2.沒有類體時(shí) class Empty
2.構(gòu)造函數(shù),在 Kotlin 中的一個(gè)類可以有一個(gè)主構(gòu)造函數(shù)以及一個(gè)或多個(gè)次構(gòu)造函數(shù)。主構(gòu)造函數(shù)是類頭的一部分
//1. 它跟在類名(與可選的類型參數(shù))后 class Person constructor(firstName: String) { /*......*/ } //2. 如果主構(gòu)造函數(shù)沒有任何注解或者可?性修飾符,可以省略這個(gè) constructor 關(guān)鍵字。 class Person(firstName: String) { /*......*/ } //3.主構(gòu)造函數(shù)不能包含任何的代碼。初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊(initializer blocks)中。
// 在實(shí)例初始化期間,初始化塊按照它們出現(xiàn)在類體中的順序執(zhí)行,與屬性初始化器交織在一起 class InitOrderDemo(name: String) { val firstProperty = "First property: $name".also(::println) init { println("First initializer block that prints ${name}") } val secondProperty = "Second property:${name.length}".also(::println) init { println("Second initializer block that prints ${name.length}") } }
輸出結(jié)果:
First property: 1
First initializer block that prints 1
Second property:1
Second initializer block that prints 1
主構(gòu)造的參數(shù)可以在初始化塊中使用。它們也可以在類體內(nèi)聲明的屬性初始化器中使用
class Customer(name: String) { val customerKey = name.toUpperCase() }
聲明屬性以及從主構(gòu)造函數(shù)初始化屬性,也可以如此寫
class Person(val firstName: String, val lastName: String, var age: Int) { /*......*/ }
與普通屬性一樣,主構(gòu)造函數(shù)中聲明的屬性可以是可變的(var)或只讀的(val)。
如果構(gòu)造函數(shù)有注解或可?性修飾符,這個(gè) constructor 關(guān)鍵字是必需的,并且這些修飾符在它前面
class Customer public @Inject constructor(name: String) { /*......*/ }
3.次構(gòu)造函數(shù):可以聲明前綴有constructor的次構(gòu)造函數(shù)
class Person { var children: MutableList<Person> = mutableListOf<>() constructor(parent: Person) { parent.children.add(this) } }
如果類有一個(gè)主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù),可以直接委托或者通過別的次構(gòu)造 函數(shù)間接委托。委托到同一個(gè)類的另一個(gè)構(gòu)造函數(shù)用 this 關(guān)鍵字即可:
class Person(val name: String) { var children: MutableList<Person> = mutableListOf<>() constructor(name: String, parent: Person) : this(name) { parent.children.add(this) } }
構(gòu)造函數(shù)的運(yùn)行順序,是先運(yùn)行主構(gòu)造函數(shù),即使為聲明,如果有init代碼塊,也會(huì)在次構(gòu)造函數(shù)體之前執(zhí)行,其實(shí)跟java的代碼塊邏輯相同
class Constructors { init { println("Init block") } constructor(i: Int) { println("Constructor") } }
運(yùn)行結(jié)果
Init block
Constructor
4.創(chuàng)建類,就像普通函數(shù)一樣調(diào)用,在kotlin中沒有new關(guān)鍵字
val invoice = Invoice() val customer = Customer("Joe Smith")
5.kotlin中所有類的超類為 Any ,存在三個(gè)方法 equals() 、hashCode() 與 toString(),默認(rèn)情況下kotlin中所有的類都是final,如果需要被繼承,則需要加open
open class Base //Class is open for inheritance //例: open class Base(p: Int) class Derived(p: Int) : Base(p) //注意:如果派生類有主構(gòu)造函數(shù),其基類必須用派生類主構(gòu)造函數(shù)的參數(shù)就地初始化
6.覆蓋方法,kotlin中對(duì)于可覆蓋的成員(或成為open開放的)覆蓋后的成員需要顯示修飾符
open class Shape { open fun draw() { /*......*/ } fun fill() { /*......*/ } } class Circle() : Shape() { override fun draw() { /*......*/ } } //Circle.draw() 函數(shù)上必須加上 override 修飾符。 //如果沒寫,編譯器將會(huì)報(bào)錯(cuò)。如果函數(shù)沒有標(biāo) 注open如 Shape.fill(),那么子類中不允許定義相同簽名的函數(shù),不論加不加override。將 open 修飾符添加到 final 類(即沒有 open 的類)的成員上不起作用。 //標(biāo)記為 override 的成員本身是開放的,也就是說(shuō),它可以在子類中覆蓋 //如果想禁止再次被覆蓋,使用final關(guān)鍵字 open class Rectangle() : Shape() { final override fun draw() { /*......*/ } }
7.覆蓋屬性,于覆蓋方法,基本一樣
//1.例子 open class Shape { open val vertexCount: Int = 0 } class Rectangle : Shape() { override val vertexCount = 4 } //2.例子 interface Shape { val vertexCount: Int } class Rectangle(override val vertexCount: Int = 4) : Shape // 總是有 4 個(gè)頂點(diǎn) class Polygon : Shape { override var vertexCount: Int = 0 // 以后可以設(shè)置為任何數(shù),val變?yōu)榱藇ar }
注意:設(shè)計(jì)一個(gè)基類時(shí),應(yīng)該避免在構(gòu)造函數(shù)、屬性初始化器以及 init 塊中使用 open 成員。
8.調(diào)用超類實(shí)現(xiàn)
8.1 派生類中可以通過super調(diào)用超類中的函數(shù)和屬性訪問器
open class Rectangle { open fun draw() { println("Drawing a rectangle") } val borderColor: String get() = "black" } class FilledRectangle : Rectangle() { override fun draw() { super.draw() println("Filling the rectangle") } val fillColor: String get() = super.borderColor }
8.2在內(nèi)部類中訪問外部類的超類,可以通過外部類名限定的super關(guān)鍵字來(lái)實(shí)現(xiàn):super@Outer
class FilledRectangle : Rectangle() { override fun draw() { /* ...... */ } override val borderColor: String get() = "black" inner class Filler { fun fill() { /* ...... */ } fun drawAndFill() { super@FilledRectangle.draw() // 調(diào)用 Rectangle 的 draw() 實(shí)現(xiàn) fill() println("Drawn a filled rectangle with color${super@FilledRectangle.borderColor}") // 使用 Rectangle 所實(shí)現(xiàn)的 borderColor 的 get() } } }
9.覆蓋規(guī)則在 Kotlin 中,實(shí)現(xiàn)繼承由下述規(guī)則規(guī)定:如果一個(gè)類從它的直接超類繼承相同成員的多個(gè)實(shí)現(xiàn),它必須 覆蓋這個(gè)成員并提供其自己的實(shí)現(xiàn)(也許用繼承來(lái)的其中之一)。為了表示采用從哪個(gè)超類型繼承的實(shí) 現(xiàn),我們使用由尖括號(hào)中超類型名限定的 super,如 super<Base>
open class Rectangle { open fun draw() { /* ...... */ } } interface Polygon { fun draw() { /* ...... */ } // 接口成員默認(rèn)就是“open”的 } class Square() : Rectangle(), Polygon { // 編譯器要求覆蓋 draw(): override fun draw() { super<Rectangle>.draw() // 調(diào)用 Rectangle.draw() super<Polygon>.draw() // 調(diào)用 Polygon.draw() } }
10.抽象類,在kotlin中可以用抽象類/成員去覆蓋一個(gè)非抽象的類/成員
open class Polygon { open fun draw() {} } abstract class Rectangle : Polygon() { abstract override fun draw() }
11.伴生對(duì)象 如果你需要寫一個(gè)可以無(wú)需用一個(gè)類的實(shí)例來(lái)調(diào)用、但需要訪問類內(nèi)部的函數(shù)(例如,工廠方法),你可 以把它寫成該類內(nèi)對(duì)象聲明中的一員。
更具體地講,如果在你的類內(nèi)聲明了一個(gè)伴生對(duì)象,你就可以訪問其成員,只是以類名作為限定符。

浙公網(wǎng)安備 33010602011771號(hào)