Kotlin-Anko學(xué)習(xí)(4) Kotlin語法-類、繼承龙巨、抽象類

本系列文章來學(xué)習(xí) Kotlin 和 Anko 插件 通過 Kotlin 開發(fā)一個 Android 項目笼呆。

Kotlin-Anko學(xué)習(xí)(1) Kotlin、Anko 介紹
Kotlin-Anko學(xué)習(xí)(2) Kotlin 語法基礎(chǔ)-基本類型
Kotlin-Anko學(xué)習(xí)(3) Kotlin 語法基礎(chǔ)-關(guān)鍵字 package旨别、Import诗赌、if、when秸弛、for铭若、while、return递览、break叼屠、continue
Kotlin-Anko學(xué)習(xí)(4) Kotlin語法-類、繼承非迹、抽象類
Kotlin-Anko學(xué)習(xí)(5) Kotlin語法-屬性环鲤、字段、接口

Kotlin 類

與Java相同憎兽,類由 class 關(guān)鍵字聲明冷离。

類聲明的組成

  • 類名 TestKot:
class TestKot{...}
  • 類頭 在類名后聲明屬性、指定其類型參數(shù)纯命、主構(gòu)造函數(shù)等西剥。 如
 /**
  * val 聲明不變的屬性,var聲明可變屬性
  * firstName  lastName 指定為String類型參數(shù) age為Int類型參數(shù)
  * Person(...) 為主構(gòu)造函數(shù)亿汞,是類頭的一部分瞭空,如果沒有類沒有聲明構(gòu)造函數(shù)(primary、secondary都沒有),系統(tǒng)會默認(rèn)生成一個無慘構(gòu)造函數(shù)咆畏,與java類似南捂。
  */
class Person(val firstName: String, val lastName: String, var age: Int) {
    // ...
}
  • 類體 TestKot: class TestKot{...} 大括號中為類體部分,如果類沒有類頭旧找,類體可以簡寫成class TestKot溺健。類體中可以包含:

構(gòu)造函數(shù)、屬性初始化钮蛛、初始化塊

  1. Kotlin 中一個類可以包含一個主構(gòu)造函數(shù)和一個或多個次構(gòu)造函數(shù)鞭缭,用關(guān)鍵字constructor修飾
  2. Kotlin 中屬性初始化可以在類頭中,也可以在類體中寫魏颓,并且可以獲得主構(gòu)造函數(shù)的參數(shù)值
  3. Kotlin 中由于主構(gòu)造函數(shù)在類頭中岭辣,不能寫初始化代碼,所以Kotlin 通過一個關(guān)鍵字 init 來包含初始化代碼塊
  • 主構(gòu)造函數(shù)(primary constructor ):
    如果主構(gòu)造函數(shù)沒有任何注解或者可見性修飾符甸饱,可以省略這個 constructor 關(guān)鍵字沦童。如下:
//省略constructor的寫法,默認(rèn)為public
class TestKot(name: String) {……}
//包含注解
class TestKot public @Inject constructor(name: String) { …… }
//聲明主構(gòu)造函數(shù)為私有
class TestKot private constructor(name: String){......}
  • 次構(gòu)造函數(shù)(secondary constructor ):
    如果類有一個主構(gòu)造函數(shù)柜候,每個次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù)搞动, 可以直接委托或者通過別的次構(gòu)造函數(shù)間接委托。委托到同一個類的另一個構(gòu)造函數(shù)用 this 關(guān)鍵字渣刷。
class Constructors(name:String) {
    //第一個屬性初始化
    val firstProperty = "First property: $name".also(::println)
    //第一個init初始化塊
    init {
        println("Init first")
    }
     //次構(gòu)造函數(shù)委托給次構(gòu)造函數(shù)(間接)
    constructor(name:String,age: Int,weight:Int):this(name,age) {
        println("Constructor name = $name age = $age weight = $weight kg")
    }
    //次構(gòu)造函數(shù)委托給主構(gòu)造函數(shù)(直接)
    constructor(name:String,age: Int):this(name) {
        println("Constructor name = $name age = $age")
    }
     //第二個init初始化塊
    init {
        println("Init second")
    }
     //第二個屬性初始化
    val secondProperty = "Second property: $name ".also(::println)
}

fun main(args: Array<String>) {
    Constructors("張三")
    print("--------------------------------------------\n")
    Constructors("李四",16)
    print("--------------------------------------------\n")
    Constructors("王五",17,55)
}

運行結(jié)果:

First property: 張三
Init first
Init second
Second property: 張三 
--------------------------------------------
First property: 李四
Init first
Init second
Second property: 李四 
Constructor name = 李四 age = 16
--------------------------------------------
First property: 王五
Init first
Init second
Second property: 王五 
Constructor name = 王五 age = 17
Constructor name = 王五 age = 17 weight = 55 kg

從以上代碼可以看出,屬性初始化和init初始化代碼塊是按順序執(zhí)行的矗烛,次構(gòu)造函數(shù)式在屬性初始化和init執(zhí)行完才開始的辅柴,所以可以把屬性初始化和init初始化代碼塊當(dāng)做主構(gòu)造函數(shù)體來理解。這樣構(gòu)造函數(shù)部分就講完了瞭吃。

類的實例化

Kotlin 中類的實例化就像普通函數(shù)一樣直接調(diào)用碌嘀,如上面的main函數(shù)中的示例,不需要new與java不同歪架,也沒有new關(guān)鍵字股冗。

Kotlin 繼承

與java不同,kotlin中類的繼承在類頭后加冒號: “Current類:Base類”

Any 超類

Kotlin 中所有類都有一個共同的超類 Any,不同于java的Object類和蚪,只有三個方法代碼如下:

public open class Any {

    public open operator fun equals(other: Any?): Boolean

    public open fun hashCode(): Int

    public open fun toString(): String
}

open關(guān)鍵字

open 標(biāo)注與 Java 中 final 相反止状,它允許其他類從這個類繼承。默認(rèn)情況下攒霹,在 Kotlin 中所有的類都是 final怯疤,抽象類不需要用open修飾。

//超類型
open class Base(p: Int)
//基類
class Current(p: Int) : Base(p)

上面代碼可以看出超類有構(gòu)造函數(shù)的話催束,其基類可以(并且必須) 用(基類型的)主構(gòu)造函數(shù)參數(shù)就地初始化集峦。

super 關(guān)鍵字

super與java類似,用于超類屬性、方法的實現(xiàn)塔淤,這里我們看派生類如何初始化超類的構(gòu)造函數(shù)

//超類型
open class Base {
    constructor(name:String ,age:Int)
    constructor(name: String,age: Int,weight:Int):this(name,age)
}
//基類 示例1
class Current(name: String, age: Int) : Base(name, age) {
  //constructor(name: String,age: Int,weight:Int):super(name,age,weight)//報錯
}
//基類 示例2
class Current(name: String,age: Int,weight:Int) : Base(name,age,weight) {
 //constructor(name: String,age: Int):super(name,age)//報錯
}
//基類 示例3
class Current : Base {
    constructor(name: String,age: Int):super(name,age)
    constructor(name: String,age: Int,weight:Int):super(name,age,weight)
}

以上代碼可以看出摘昌,超類沒有主構(gòu)造函數(shù),基類可以通過主構(gòu)造函數(shù)初始化超類的任意一個次構(gòu)造函數(shù)高蜂,在此基礎(chǔ)上聪黎,基類的次構(gòu)造函數(shù)不能通過super來初始化超類的其他次構(gòu)造函數(shù),如示例1,2妨马;基類也可以不聲明主構(gòu)造函數(shù)挺举,通過次構(gòu)造函數(shù)super來初始化對應(yīng)的次構(gòu)造函數(shù),如示例3烘跺。

override 關(guān)鍵字

Kotlin 中 override 只能修飾父類顯式標(biāo)注可覆蓋的成員(開放open)湘纵,父類中沒有顯式標(biāo)注的成員在其子類中不允許定義相同簽名的函數(shù)。

覆蓋方法

open class Base {
    open fun v() {}
    fun nv() {}
}
//示例1
class Bar1() : Base() {
    override fun v() {}
//     override  fun nv(){}//error:'nv' in 'Base' is final and cannot be overridden
//     fun nv(){}//error: 'nv' hides member of supertype 'Base' and needs 'override' modifier
}
//示例2
class Foo {
//    open val x: Int get() { return 1 } //Warning:'open' has no effect in a final class
//示例3
open class Bar2() : Base() {
    final override fun v() {}
}

示例1:說明父類的顯式標(biāo)注方法滤淳,在子類中可以通過override修飾的相同方法覆蓋梧喷,對于沒有開放的函數(shù), 不論加不加 override脖咐,都不允許定義與父類相同簽名的方法铺敌。
示例2:說明在一個 final 類中(沒有用 open 標(biāo)注的類),open修飾的方法沒有用
示例3:說明子類重寫的方法如果想在屁擅,子類的子類中不被繼續(xù)重寫偿凭,可以在override前用final 進行修飾。

覆蓋屬性

open class Foo {
    open val x: Int =1
    open val y: Int get(){return 5}
}
示例1
class Bar1 : Foo() {
    override val x: Int = 2
    init{
        print("x= $x \n")
        print("y= $y \n")
    }

}
示例2
class Bar2 : Foo(){
    override var x : Int = 3
    init{
        print("x= $x")
    }
}
fun main(args: Array<String>) {
    Bar1()
    Bar2()
}

輸出結(jié)果:

x= 2 
x= 5
x= 3

重寫屬性的規(guī)則也是通過override進行修飾派歌,并且派生類的重寫的屬性必須兼容超類的屬性弯囊,示例1可以看出
聲明的屬性由具有初始化器的屬性或者具有 getter 方法的屬性覆蓋 ,示例2可以看出用一個 var 屬性覆蓋一個 val 屬性是可以的胶果,本質(zhì)上var的get方法覆蓋了val的get方法匾嘱,并且在派生類額外生成一個set方法。

調(diào)用超類的實現(xiàn)

調(diào)用超類中的方法與java相同早抠,通過super關(guān)鍵字修飾霎烙,屬性屬kotlin獨有的。

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
    init{
        println("x= $x")
    }
}
fun main(args: Array<String>) {
    Bar().f()
}

輸出結(jié)果:

x= 2
Foo.f()
Bar.f()

以上就是派生類中調(diào)用超類具體的實現(xiàn)蕊连,跟java相似悬垃。

覆蓋規(guī)則

既有繼承又有接口的實現(xiàn)

Kotlin 中一個類從它的直接超類繼承相同成員的多個實現(xiàn), 它必須覆蓋這個成員并提供其自己的實現(xiàn)咪奖。 為了表示采用從哪個超類型繼承的實現(xiàn)盗忱,我們使用由尖括號中超類型名限定的 super,如 super<Base>

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

interface B {
    fun f() { println("B") } // 接口成員默認(rèn)就是“open”的
    fun b() { println("b") }
}

class C() : A(), B {
    init{
        println("C()")
    }
    // 編譯器要求覆蓋 f():
    override fun f() {
        super<A>.f() // 調(diào)用 A.f()
        super<B>.f() // 調(diào)用 B.f()
  }
}
fun main(args: Array<String>) {
     C().f()
}

輸出結(jié)果:

C()
A
B

首先在派生類既有繼承又有接口羊赵,并且超類趟佃、接口中存在相同的方法扇谣,派生類必須重寫該方法,并且通過
surper<A>.f() 尖括號中表明實現(xiàn)哪個父類的方法闲昭,并且這里說明一下kotlin中接口中的方法默認(rèn)是open的罐寨。

內(nèi)部類中訪問外部類超類的實現(xiàn)

open class Foo {
    open fun f() { println("Foo.f()") }
    open val x: Int get() = 1
}

class Bar : Foo() {
    override fun f() {  println("Bar.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
        }
    }
}
fun main(args: Array<String>) {
    Bar().Baz().g()
}

輸出結(jié)果:

Foo.f()
1

內(nèi)部類需要實現(xiàn)外部類的屬性和方法,我們super@Outer().f()序矩、super@Outer.x來實現(xiàn)鸯绿。

抽象類

kotlin 中抽象類和java相同,通過 abstract 關(guān)鍵字來修飾簸淀,抽象類中可以包含抽象的方法或?qū)傩浴?/p>

open class Base {
    open fun f() {}
}
abstract class Bar : Base() {
    abstract val x :Int
    override abstract fun f()
    open fun g(){println("Bar.g()")}
}
class Child() :Bar(){
    override var x: Int =2
    override fun g() {
        super.g()
        println("Child g()")
    }
    override fun f() {
       println("Child f()")
    }
}
fun main(args: Array<String>) {
  var child = Child()
    child.g()
    child.f()   
}

輸出結(jié)果:

Bar.g()
Child g()
Child f()

上面的代碼可以看出瓶蝴,非抽象的超類可以派生出抽象類,并且開放的方法可以被重寫成抽象方法租幕,抽象方法是不允許有方法體的舷手,abstract 修飾的屬性或方法默認(rèn)是open的。這里與接口不同劲绪,接口中的方法默認(rèn)抽象的也是默認(rèn)開放的男窟,抽象類中的方法只有抽象的方法才是默認(rèn)open的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贾富,一起剝皮案震驚了整個濱河市歉眷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颤枪,老刑警劉巖汗捡,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異畏纲,居然都是意外死亡凉唐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門霍骄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淡溯,你說我怎么就攤上這事读整。” “怎么了咱娶?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵米间,是天一觀的道長。 經(jīng)常有香客問我膘侮,道長屈糊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任琼了,我火速辦了婚禮逻锐,結(jié)果婚禮上夫晌,老公的妹妹穿的比我還像新娘。我一直安慰自己昧诱,他們只是感情好晓淀,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盏档,像睡著了一般凶掰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜈亩,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天懦窘,我揣著相機與錄音,去河邊找鬼稚配。 笑死畅涂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的药有。 我是一名探鬼主播毅戈,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼愤惰!你這毒婦竟也來了苇经?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤宦言,失蹤者是張志新(化名)和其女友劉穎扇单,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奠旺,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡蜘澜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了响疚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鄙信。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖忿晕,靈堂內(nèi)的尸體忽然破棺而出装诡,到底是詐尸還是另有隱情,我是刑警寧澤践盼,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布鸦采,位于F島的核電站,受9級特大地震影響咕幻,放射性物質(zhì)發(fā)生泄漏渔伯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一肄程、第九天 我趴在偏房一處隱蔽的房頂上張望锣吼。 院中可真熱鬧选浑,春花似錦、人聲如沸吐限。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诸典。三九已至描函,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間狐粱,已是汗流浹背舀寓。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肌蜻,地道東北人互墓。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像蒋搜,于是被迫代替她去往敵國和親篡撵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359