原文地址
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)做限定符盟蚣。