Kotlin 類和對象(六)
上一篇我們講了Kotlin的循環(huán)還有條件控制Kotlin 循環(huán)和條件控制(五) ,這次我們將要學(xué)習(xí)一個Kotlin的類與對象.
類:
Kotlin 中的類使用的也是 class 關(guān)鍵字聲明,類由類名爽冕、類頭(指定它的類型參數(shù)、主構(gòu)造器等等)和類體組成阳准,用花括號包圍棠枉。類頭和類體都是可選的套硼;如果類沒有類體則花括號可以省略。
//有類體的類
class Test {
}
//沒有類體的類
class Test
構(gòu)造器:
構(gòu)造器?
構(gòu)造器是干哈的?
小白可能會很懵逼啊,是的構(gòu)造器是用來初始化一個類的,比如我這個類是沸騰的白開水,我需要使用它,我怎么才能擁有它呢?
1.直接用鍋煮.
2.用熱水壺.
3.用太陽曬
有的同學(xué)可能說這是不同的方式去成功拿到開水啊,是的構(gòu)造器也是這樣,我們的類可以有多個構(gòu)造,如果你不寫,也是有的!只是隱藏了起來,以免大家看見太多代碼頭暈!好了下面我來細(xì)致解釋一下各種構(gòu)造器,以及各做方式去初始化一個類:
這里有4個類,他們什么都沒有,但是他們都是有構(gòu)造的,并且是一樣的構(gòu)造,只是我們的寫法可以去省略這些代碼
這里的constructor 是他們省略的一個構(gòu)造,所以記住一句話,只要是類就有構(gòu)造!
如果構(gòu)造函數(shù)有注解或可見性修飾符,這個 constructor 關(guān)鍵字是必需的允华,并且這些修飾符在它前面,像下面這種寫在類名旁邊的構(gòu)造就是這個類的主構(gòu)造,可以傳遞不同的內(nèi)容去初始化這個類.當(dāng)然直接指定var,val這種參數(shù)可以讓這個參數(shù)變成這個類的成員,在類中使用
主構(gòu)造函數(shù)不能包含任何的代碼井联。初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊(initializer blocks)中卜壕。
當(dāng)然有主就有次,次構(gòu)造呢就是我之前舉得例子那樣,有很多種方式,比如用太陽把水曬沸騰...
開個玩笑哦,繼續(xù)看:
這里我就給Dad1 這個類寫了一個不同的構(gòu)造,主構(gòu)造是一個空的,而次構(gòu)造需要一個String類型的name來初始化這個類,每個次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù), 可以直接委托或者通過別的次構(gòu)造函數(shù)間接委托烙常。委托到同一個類的另一個構(gòu)造函數(shù)用 this 關(guān)鍵字即可,那么怎去委托同一個類的其他構(gòu)造呢?請看第三個次構(gòu)造,第三個次構(gòu)造就是通過傳入2個參數(shù)去委托第二個構(gòu)造,最后在委托回主構(gòu)造.
如果你不希望你的類有一個公有構(gòu)造函數(shù)轴捎,你需要聲明一個帶有非默認(rèn)可見性的空的主構(gòu)造函數(shù):
還有一種直接給構(gòu)造中參數(shù)復(fù)制的操作,在繼承中可以發(fā)揮一些用途,其他的恕我還沒有探索到...
創(chuàng)建類的實例
在Kotlin里面創(chuàng)建實列和Java不一樣,變得更加簡單直接像調(diào)用函數(shù)一樣,創(chuàng)建,注意: 不用使用new了! 不用使用new了! 不用使用new了!
創(chuàng)建嵌套類、內(nèi)部類和匿名內(nèi)部類的類實例在[嵌套類]我們下一篇再講蚕脏。
繼承
在Kotlin中有一個共同超類,也就是Java中的Object ,在Kotlin 里面加Any,但是Any類中只有equals()侦副、hashCode()和toString() 三個函數(shù)外沒有其他任何成員了.
怎么去繼承一個類呢?
很簡單就是使用: 你要繼承的類,在父類前面加上open,這里的open 其實就是指可以被繼承,Kotlin 里面所有的類默認(rèn)是final ,需要繼承的類就指定open,并且需要指定構(gòu)造,就是下面的箭頭所指的構(gòu)造去初始化父類.
淡然也可以通過關(guān)鍵字super去初始化父類
覆蓋方法與屬性
覆蓋方法和屬性需要加上 override 這個關(guān)鍵字 , 如果不想子類覆蓋就在前面指定 final 這樣子類就沒辦法覆蓋了.不僅可以在成員位置覆蓋,在主構(gòu)造覆蓋也是可以的.
調(diào)用超類實現(xiàn)
派生類中的代碼可以使用 super 關(guān)鍵字調(diào)用其超類的函數(shù)與屬性訪問器的實現(xiàn):
open class Foo {
open fun f() { println("Foo.f()") }
open val x: Int get() = 1
}
class Bar : Foo() {
override fun f() {
super.f()
println("Bar.f()")
}
override val x: Int get() = super.x + 1
}
在一個內(nèi)部類中訪問外部類的超類,可以通過由外部類名限定的 super 關(guān)鍵字來實現(xiàn):super@Outer
:
class Bar : Foo() {
override fun f() { /* …… */ }
override val x: Int get() = 0
inner class Baz {
fun g() {
super@Bar.f() // 調(diào)用 Foo 實現(xiàn)的 f()
println(super@Bar.x) // 使用 Foo 實現(xiàn)的 x 的 getter
}
}
}
覆蓋規(guī)則
在 Kotlin 中驼鞭,實現(xiàn)繼承由下述規(guī)則規(guī)定:如果一個類從它的直接超類繼承相同成員的多個實現(xiàn)秦驯, 它必須覆蓋這個成員并提供其自己的實現(xiàn)(也許用繼承來的其中之一)。 為了表示采用從哪個超類型繼承的實現(xiàn)挣棕,我們使用由尖括號中超類型名限定的 super译隘,如 super<Base>
:
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // 接口成員默認(rèn)就是“open”的
fun b() { print("b") }
}
class C() : A(), B {
// 編譯器要求覆蓋 f():
override fun f() {
super<A>.f() // 調(diào)用 A.f()
super<B>.f() // 調(diào)用 B.f()
}
}
同時繼承 A
和 B
沒問題亲桥,并且 a()
和 b()
也沒問題因為 C
只繼承了每個函數(shù)的一個實現(xiàn)。 但是 f()
由 C
繼承了兩個實現(xiàn)细燎,所以我們必須在 C
中覆蓋 f()
并且提供我們自己的實現(xiàn)來消除歧義两曼。
抽象類
類和其中的某些成員可以聲明為 abstract。 抽象成員在本類中可以不用實現(xiàn)玻驻。 需要注意的是悼凑,我們并不需要用 open
標(biāo)注一個抽象類或者函數(shù)——因為這不言而喻。
我們可以用一個抽象成員覆蓋一個非抽象的開放成員
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
總結(jié):
Kotlin的類和對象是最基礎(chǔ)的東西,也是對于小白入門比較困難的東西,大家多多理解,理解是最重要的,加油!