# 類與繼承
## 類
Kotlin 中的類使用 `class` 關鍵字聲明:
``` kotlin
class Invoice {
}
```
類由類名、類頭(指定它的類型參數、主構造器等等)和類體組成,用花括號包圍。類頭和類體都是可選的;如果類沒有類體則花括號可以省略。
``` kotlin
class Empty
```
### 構造器
Kotlin 中一個類可以有一個**主構造器**和一個或多個**輔構造器**。主構造器是類頭的一部分:它在類名后面(類參數是可選的)。
``` kotlin
class Person constructor(firstName: String) {
}
```
如果主構造器沒有注解或可見性修飾符,則 `constructor` 關鍵字可以省略:
``` kotlin
class Person(firstName: String) {
}
```
主構造器不能包含任何代碼。初始化代碼可以放在有*init*關鍵字前綴的**初始化塊**中:
``` kotlin
class Customer(name: String) {
init {
logger.info("Customer initialized with value ${name}")
}
}
```
注意主構造器的參數可以在初始化塊中使用。它們也能在類體的屬性初始化聲明中使用:
``` kotlin
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
```
事實上,聲明屬性并在構造器初始化它們,Kotlin 有一個簡潔的語法:
``` kotlin
class Person(val firstName: String, val lastName: String, var age: Int) {
// ...
}
```
常規屬性和許多相同的方式一樣,屬性在主構造器中聲明可以是可變的(`var`) 或只讀的(`val`)。
如果構造器有注解或可見性修飾符,那么 `constructor` 關鍵字是必須的,并且這個修飾符在它前面:
``` kotlin
class Customer public @Inject constructor(name: String) { ... }
```
更詳細的信息查看 [可見性修飾](visibility-modifiers.md).
#### 輔構造器
類還可以與 `constructor` 前綴結合聲明**輔構造器**:
``` kotlin
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
```
如果該類有一個主構造器,每個輔構造器需要委托給主構造器,
``` kotlin
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
```
如果一個非抽象類沒有聲明構造器(主或輔),它將生成一個無參主構造器。該構造器的可見性將為公開。如果你不想你的類有一個公開的構造器,你需要聲明一個空的非默認可見的主構造器:
``` kotlin
class DontCreateMe private constructor () {
}
```
> [info]注意:在JVM上,如果構造器的所有參數都有默認值,則編譯器將生成一個附加的無參構造器并用默認值初始化。這讓 Kotlin 更易于使用一些庫,像 Jackson 或 JPA 通過無參構造器創建類實例。
>
> ``` kotlin
> class Customer(val customerName: String = "")
> ```
### 創建類實例
要創建一個類的實例,我們只要像普通函數一個調用構造器:
``` kotlin
val invoice = Invoice()
val customer = Customer("Joe Smith")
```
注意 Kotlin 沒有 `new` 關鍵字。
### 類成員
類可以包含
* 構造器和初始化塊
* [函數](../functions-and-lambdas/functions.md)
* [屬性](properties-and-fields.md)
* [嵌套和內部類](nested-classes.md)
* [對象聲明](object-declarations.md)
## 繼承
Kotlin 中所有的類都有一個公共的超類 `Any`,這是一個默認的超類,不用超類聲明:
``` kotlin
class Example // 隱含的從 Any 繼承
```
`Any` 不是 `java.lang.Object`;特別要指出的是,它除了 `equals()`、`hashCode()` 和 `toString()` 之外再沒有其它的成員。更多信息請查閱[Java interoperability](java-interop.html#object-methods) 章節。
要明確地聲明的一個超類,我們在類頭的冒號后面放置類型:
``` kotlin
open class Base(p: Int)
class Derived(p: Int) : Base(p)
```
如果類有主構造器,則基類可以(并且必須)使用主構造器的參數初始化。
如果類沒有主構造器,那么每個輔構造器都得使用 `super` 關鍵字初始化基類,或是委托給其它構造器來做。注意這種情況下不同的輔構造器可以調用不同的基類構造器:
``` kotlin
class MyView : View {
constructor(ctx: Context) : super(ctx) {
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
}
}
```
類上的 `open` 注解與 Java 的 `final` 相反:它允許別的類從這個類繼承。默認情況下,Kotlin 中所有的類都是 final,類似[Effective Java](http://www.oracle.com/technetwork/java/effectivejava-136174.html)的 Item 17: *Design and document for inheritance or else prohibit it*
### 覆蓋方法
正如我們之前所說,在 Kotlin 中我們堅持明確地制造東西。所以與 Java 不同,Kotlin 必需為可覆蓋的成員作出明確的注解(我們叫做 `open`)才能被覆蓋:
``` kotlin
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
```
對于 `Derived.v()` 來說 `override` 注解是必需的。如果未找到它,編譯器就會提出抗議。如果函數上沒有 `open` 注解,比如 `Base.nv()`,在子類中聲明一個相同簽名的方法是非法的,或者說不管有沒有 `override`,在 final 類(例如一個沒有 `open` 注解的類)中開放成員都是禁止的。
成員被標記為 `overridde` 表示自身開放,意即它可以被子類覆蓋。如果你想要禁止再次被覆蓋,則使用 `final` 關鍵字:
``` kotlin
open class AnotherDerived() : Base() {
final override fun v() {}
}
```
### 覆蓋屬性
覆蓋屬性與覆蓋方法類似。超類上的屬性聲明在衍生類中重復聲明必須以 `override` 開頭,并且它們必須具有一致的類型。每個聲明的屬性都能被另一個初始化程序或帶有 getter 方法的屬性覆蓋。
``` kotlin
open class Foo {
open val x: Int get { ... }
}
class Bar1 : Foo() {
override val x: Int = ...
}
```
你可以用一個 `var` 覆蓋一個 `val`,但反過來則不行。這樣的原因是一個 `val` 屬性本質上聲明了一個 getter 方法,而覆蓋成 `var` 則是在衍生類中另外聲明一個 setter 方法。
注意你可以在主構造器中的屬性聲明部分使用 `override` 關鍵詞。
``` kotlin
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count: Int = 0
}
```
### 覆蓋規則
在 Kotlin 中,繼承的實現通過下面的規則控制:如果一個類從它隱含超類中繼承相同成員的一些實現,它必須覆蓋這個成員并且提供它自己的實現(也許使用某個已繼承的)。要在所繼承的實現里表示這個超類,我們合法地使用 `super` 和在尖括號內的超類名,例如 `super<Base>`:
``` kotlin
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()
}
}
```
這樣很好地從 `A` 和 `B` 繼承,而且我們在 `C` 僅僅繼承每個函數的一個實現時也不會在 `a()` 和 `b()` 間出現問題。但是對于 `f()` 我們有兩個實現通過 `C` 繼承,因此我們不得不在 `C` 中覆蓋 `f()` 并提供我們自己的實現來排除岐義。
## 抽象類
類和它的一些成員可以聲明為 `abstract`。一個抽象成員在類中沒有實現。注意我們不需要注釋抽象類或者函數為 open ————它不需要說出來。
我們可以把一個 open 成員覆蓋成一個抽象的
``` kotlin
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
```
## 友元對象
Kotlin 里與 Java 或 C# 不一樣的是,類沒有靜態方法。在大多數情況下,推薦簡單地使用包級函數替代。
如果你需要寫一個函數讓其可以不用類實例就能調用但又要訪問這個類的內部(舉例:一個工廠方法),你可以把它寫成一個類內部的[對象聲明](object-declarations.md)成員
更確切地說,如果你在你的類內部聲明一個[友元對象](object-declarations.md#companion-objects),你就可以用和 Java/C# 中調用靜態方法一樣的語法調用其成員而只需要一個合法的類名。