Kotlin類(lèi)和繼承

原文地址

Classes

類(lèi)在Kotlin中使用class關(guān)鍵字被聲明

class Invoice {
}

類(lèi)聲明由類(lèi)名和類(lèi)頭組成(指定它的類(lèi)型參數(shù)逝钥,主要構(gòu)造函數(shù)等等)凯旋。被花闊號(hào)括起來(lái)的類(lèi)體他嫡。類(lèi)頭和類(lèi)體是可選的颖医。如果那個(gè)類(lèi)沒(méi)有類(lèi)體枉长,花括號(hào)能夠被省略冀续。

class Empty

Constructors(構(gòu)造器)

在Kotlin中一個(gè)類(lèi)能夠有一個(gè)主要構(gòu)造函數(shù)和一個(gè)或多個(gè)次級(jí)構(gòu)造函數(shù)。首要構(gòu)造函數(shù)是類(lèi)頭的一部分:他在類(lèi)名后面(可選類(lèi)型參數(shù))

class Person constructor(firstName: String) {
}

如果主要構(gòu)造函數(shù)沒(méi)有任何注解和可見(jiàn)修飾符必峰,constructor關(guān)鍵字可以被省略:

class Person(firstName: String) {
}

主要構(gòu)造函數(shù)不能包含任何代碼洪唐。初始化代碼能夠放到以init為前綴的初始化器中。

class Customer(name: String) {
    init {
        logger.info("Customer initialized with value ${name}")
    }
}

注意:主要構(gòu)造函數(shù)的參數(shù)能夠被用于初始化代碼塊中吼蚁。他們也能被用于類(lèi)體中的屬性值初始化凭需。

class Customer(name: String) {
    val customerKey = name.toUpperCase()
}

事實(shí)上,為了聲明屬性值并且在主要構(gòu)造函數(shù)中初始化肝匆,Kotlin有一個(gè)簡(jiǎn)潔的語(yǔ)法:

class Person(val firstName: String, val lastName: String, var age: Int) {
    // ...
}

普通的屬性值很相似粒蜈,在主要構(gòu)造函數(shù)中聲明的屬性值有能夠被改變(var)或者只讀(val)兩種
如果一個(gè)構(gòu)造函數(shù)有注解或者可見(jiàn)修飾符,constructor關(guān)鍵字是被需要的旗国,并且修飾符在它之前

class Customer public @Inject constructor(name: String) { ... }

關(guān)于更多細(xì)節(jié)枯怖,參看Visibility Modifiers

Secondary Constructors(次級(jí)構(gòu)造器)

類(lèi)也能被聲明為以constructor關(guān)鍵字為前綴的次級(jí)構(gòu)造器。

class Person {
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

如果類(lèi)有一個(gè)主要構(gòu)造器能曾,每一個(gè)次級(jí)構(gòu)造器需要去代理主構(gòu)造器嫁怀,直接或者間接的方式通過(guò)另一個(gè)次級(jí)構(gòu)造器设捐。代理同一類(lèi)的另一個(gè)構(gòu)造器使用this關(guān)鍵字:

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

如果一個(gè)非抽象的類(lèi)不聲明任何構(gòu)造器(主要的或者次級(jí)的),它將生成一個(gè)沒(méi)有參數(shù)的構(gòu)造器塘淑。構(gòu)造器的可見(jiàn)性將是public。如果你不想你的類(lèi)有一個(gè)公共構(gòu)造器蚂斤。你需要聲明一個(gè)不帶默認(rèn)可見(jiàn)性的空的構(gòu)造器:

class DontCreateMe private constructor () {
}

注意:在JVM中存捺,如果所有主要構(gòu)造器的參數(shù)有默認(rèn)值,編譯器將會(huì)生成一個(gè)額外的無(wú)參使用默認(rèn)值的構(gòu)造器曙蒸。這將使Kotlin使用像Jackson或者JPA創(chuàng)建class實(shí)例通過(guò)無(wú)參構(gòu)造函數(shù)變得容易捌治。

class Customer(val customerName: String = "")

Creating instances of classes(創(chuàng)建類(lèi)實(shí)例)

為了創(chuàng)建一個(gè)類(lèi)的實(shí)例,我們調(diào)用構(gòu)造器如果它是一個(gè)常規(guī)的函數(shù):

val invoice = Invoice()

val customer = Customer("Joe Smith")

注意Kotlin沒(méi)有new關(guān)鍵字
創(chuàng)建一個(gè)嵌套的纽窟,內(nèi)部的肖油,匿名內(nèi)部類(lèi)的實(shí)例在 Nested classes中有描述

Class Members(類(lèi)成員)

類(lèi)能夠包含:

  • 構(gòu)造參數(shù)和初始化器
  • 函數(shù)
  • 屬性值
  • 嵌套和內(nèi)部類(lèi)
  • 對(duì)象聲明

Inheritance(繼承)

所有在Kotlin中的類(lèi)有一個(gè)公共的超類(lèi)Any。這是一個(gè)默認(rèn)的沒(méi)有任何超類(lèi)型被聲明的超類(lèi)臂港。
···
class Example // Implicitly inherits from Any
···

Any 不是java.lang.object森枪;在特殊情況下,它不包含任何的成員變量除了equals()审孽, hashCode()toString().更多細(xì)節(jié)請(qǐng)參考Java interoperability

為了聲明一個(gè)明確的超類(lèi)型县袱,我們把類(lèi)型放置到類(lèi)標(biāo)題的分號(hào)后:

open class Base(p: Int)

class Derived(p: Int) : Base(p)

如果類(lèi)有一個(gè)首要的構(gòu)造函數(shù),基本類(lèi)型必須在這里初始化并使用首要構(gòu)造函數(shù)的參數(shù)佑力。
如果一個(gè)類(lèi)沒(méi)有首要構(gòu)造函數(shù)式散,那么每個(gè)次級(jí)構(gòu)造函數(shù)必須初始化基本類(lèi)型使用super關(guān)鍵字〈虿或者委托給另一個(gè)構(gòu)造函數(shù)做這件事暴拄。注意在這種情況下不同的次級(jí)構(gòu)造函數(shù)可以調(diào)用不同的基本類(lèi)型的構(gòu)造函數(shù)。

class MyView : View {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

在一個(gè)類(lèi)上的open注解是java’s final的反義詞编饺;它允許其他類(lèi)繼承于這個(gè)類(lèi)乖篷。默認(rèn)情況下,在Kotlin中所有的類(lèi)是final的反肋,這是符合Effective Java, Item 17: Design and document for inheritance or else prohibit it.

Overriding Methods(重寫(xiě)方法)

正如我們之上所提出的那伐,在Kotlin中,我們執(zhí)著于讓事情變的明確石蔗,不像Java罕邀,Kotlin需要明確的的注解對(duì)于可重寫(xiě)成員(我們稱(chēng)之為open)和要重寫(xiě)的。

open class Base {
    open fun v() {}
    fun nv() {}
}
class Derived() : Base() {
    override fun v() {}
}

Derived.v()需要有重寫(xiě)注釋?zhuān)绻笔Я搜啵幾g器將會(huì)報(bào)警诉探。如果沒(méi)有open注解在函數(shù)上,像Base.nv(),用相同的簽名聲明方法在子類(lèi)中是非法的棍厌,不管有沒(méi)有override關(guān)鍵字肾胯。在一個(gè)final類(lèi)中(也就是沒(méi)有open注解的類(lèi))竖席,open成員是被禁止的。
一個(gè)成員被標(biāo)記為override它本身是open敬肚,也就是可能在子類(lèi)中被重寫(xiě)毕荐。如果你想禁止重寫(xiě),用final:

open class AnotherDerived() : Base() {
    final override fun v() {}
}

Overriding Properties(重寫(xiě)屬性)

重寫(xiě)屬性的工作方式與重寫(xiě)方法相同;在超類(lèi)中聲明的屬性在子類(lèi)中再次聲明必須以override為開(kāi)始艳馒,并且他們必須有一個(gè)可兼容的類(lèi)型憎亚。每個(gè)聲明的屬性能夠被重寫(xiě)通過(guò)一個(gè)帶有初始化器的屬性或者有g(shù)etter函數(shù)的屬性。

open class Foo {
    open val x: Int get { ... }
}

class Bar1 : Foo() {
    override val x: Int = ...
}

你也可以用一個(gè)var屬性重寫(xiě)一個(gè)val屬性弄慰,但反之則不然第美。這樣被允許是因?yàn)関al屬性必須聲明一個(gè)getter函數(shù),把它當(dāng)做一個(gè)var重寫(xiě)需要額外的聲明一個(gè)setter函數(shù)在子類(lèi)中陆爽。
注意:你能夠使用override關(guān)鍵字作為首要構(gòu)造函數(shù)的部分聲明屬性什往。

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}

Overriding Rules(重寫(xiě)規(guī)則)

在Kotlin,繼承實(shí)現(xiàn)是被如下規(guī)則管制:如果一個(gè)類(lèi)從它的直接超類(lèi)中繼承了很多同一成員的實(shí)現(xiàn)慌闭,它必須重寫(xiě)這個(gè)成員并且提供它自己的實(shí)現(xiàn)(可能别威,使用被繼承的某一個(gè))。為了表示被繼承實(shí)現(xiàn)的超類(lèi)型贡必,我們可以使用超限定名通過(guò)尖括號(hào)中的超類(lèi)型名稱(chēng)兔港,也就是super<Base>:

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

interface B {
    fun f() { print("B") } // interface members are 'open' by default
    fun b() { print("b") }
}

class C() : A(), B {
    // The compiler requires f() to be overridden:
    override fun f() {
        super<A>.f() // call to A.f()
        super<B>.f() // call to B.f()
    }
}

同時(shí)繼承A和B是ok的,對(duì)于a()和b()這里沒(méi)有問(wèn)題因?yàn)閏繼承了這些函數(shù)的一種實(shí)現(xiàn)仔拟。但是對(duì)于f()我們有兩種被c繼承的實(shí)現(xiàn),因此我們必須重寫(xiě)在c中重寫(xiě)f()并且提供我們自己的實(shí)現(xiàn)去消除歧義衫樊。

Abstract Classes(抽象類(lèi))

一個(gè)類(lèi)和它的成員可能被聲明為abstract。一個(gè)抽象的成員在它的類(lèi)中沒(méi)有實(shí)現(xiàn)利花。注意我們不需要注解一個(gè)抽象類(lèi)或者函數(shù)通過(guò)open-它是不需要說(shuō)明的
我們可以重寫(xiě)一個(gè)非抽象open成員通過(guò)一個(gè)抽象的

open class Base {
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

Companion Objects(伴隨體)

在Kotlin中科侈,不像Java或者C#,類(lèi)沒(méi)有靜態(tài)成員炒事,多數(shù)情況下臀栈,建議只使用包級(jí)別的函數(shù)。
如果需要一個(gè)沒(méi)有類(lèi)實(shí)例但能被訪問(wèn)類(lèi)內(nèi)部且能夠被調(diào)用的函數(shù)(例如挠乳,一個(gè)工廠函數(shù))权薯,你可以把它寫(xiě)為一個(gè)類(lèi)中的object declaration 成員
更具體的說(shuō),如果你在類(lèi)中聲明一個(gè) companion object,你將能夠
調(diào)用它的函數(shù)使用相同的語(yǔ)法像調(diào)用Java/C#中的靜態(tài)函數(shù)那樣睡扬,僅僅使用類(lèi)名稱(chēng)當(dāng)做限定符盟蚣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卖怜,隨后出現(xiàn)的幾起案子屎开,更是在濱河造成了極大的恐慌,老刑警劉巖马靠,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奄抽,死亡現(xiàn)場(chǎng)離奇詭異蔼两,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)逞度,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)额划,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人档泽,你說(shuō)我怎么就攤上這事锁孟。” “怎么了茁瘦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)储笑。 經(jīng)常有香客問(wèn)我甜熔,道長(zhǎng),這世上最難降的妖魔是什么突倍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任腔稀,我火速辦了婚禮,結(jié)果婚禮上羽历,老公的妹妹穿的比我還像新娘焊虏。我一直安慰自己,他們只是感情好秕磷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布诵闭。 她就那樣靜靜地躺著,像睡著了一般澎嚣。 火紅的嫁衣襯著肌膚如雪疏尿。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,050評(píng)論 1 291
  • 那天易桃,我揣著相機(jī)與錄音褥琐,去河邊找鬼。 笑死晤郑,一個(gè)胖子當(dāng)著我的面吹牛敌呈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播造寝,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼磕洪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了匹舞?” 一聲冷哼從身側(cè)響起褐鸥,我...
    開(kāi)封第一講書(shū)人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赐稽,沒(méi)想到半個(gè)月后叫榕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體浑侥,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年晰绎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寓落。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荞下,死狀恐怖伶选,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尖昏,我是刑警寧澤仰税,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站抽诉,受9級(jí)特大地震影響陨簇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迹淌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一河绽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧唉窃,春花似錦耙饰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至矮嫉,卻和暖如春削咆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蠢笋。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工拨齐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昨寞。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓瞻惋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親援岩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歼狼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容