一.類
Kotlin 中使用關鍵字 class 聲明類
class Invoice { /*……*/ }
1.構造函數
在 Kotlin 中的一個類可以有一個主構造函數以及一個或多個次構造函數。主構造函數是類頭的一部分:它跟在類名(與可選的類型參數)後。
class Person constructor(firstName: String) { /*……*/ }
如果主構造函數沒有任何註解或者可見性修飾符,可以省略這個 constructor 關鍵字。
class Person(firstName: String) { /*……*/ }
2.次構造函數
請注意,初始化塊中的代碼實際上會成爲主構造函數的一部分。委託給主構造函數會作爲次構造函數的第一條語句,因此所有初始化塊與屬性初始化器中的代碼都會在次構造函數體之前執行。即使該類沒有主構造函數,這種委託仍會隱式發生,並且仍會執行初始化塊:
class Constructors(name:String) { //主構造函數
init { //初始化
println("Init block")
}
constructor(i: Int) { //次構造函數
println("Constructor")
}
constructor(i: Int,a:String) { //次構造函數
println("Constructor")
}
}
3.創建類的實例
要創建一個類的實例,我們就像普通函數一樣調用構造函數:
val invoice = Invoice()
val customer = Customer("Joe Smith")
注意 Kotlin 並沒有 new 關鍵字。
4.繼承
在 Kotlin 中所有類都有一個共同的超類 Any
,這對於沒有超類型聲明的類是默認超類
class Example // 從 Any 隱式繼承
如需聲明一個顯式的超類型,請在類頭中把超類型放到冒號之後:
open class Base(p: Int) //顯式的超類型
class Derived(p: Int) : Base(p)
如果派生類有一個主構造函數,其基類可以(並且必須) 用派生類主構造函數的參數就地初始化。
如果派生類沒有主構造函數,那麼每個次構造函數必須使用 super 關鍵字初始化其基類型,或委託給另一個構造函數做到這一點。 注意,在這種情況下,不同的次構造函數可以調用基類型的不同的構造函數:
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
5.覆蓋方法
我們之前提到過,Kotlin 力求清晰顯式。因此,Kotlin 對於可覆蓋的成員(我們稱之爲開放open)以及覆蓋後的成員需要顯式修飾符:
Base.v()
函數上必須加上 override 修飾符。如果沒寫,編譯器將會報錯。 如果函數沒有標註 open 如 Base.nv()
,那麼子類中不允許定義相同簽名的函數, 不論加不加 override。將 open 修飾符添加到 final 類(即沒有 open 的類(Derived)或方法(Base.nv()))的成員上不起作用。
標記爲 override 的成員本身是開放的,也就是說,它可以在子類中覆蓋。如果你想禁止再次覆蓋,使用 final 關鍵字:
6.覆蓋屬性
屬性覆蓋與方法覆蓋類似;在超類中聲明然後在派生類中重新聲明的屬性必須以 override 開頭,並且它們必須具有兼容的類型。 每個聲明的屬性可以由具有初始化器的屬性或者具有 get
方法的屬性覆蓋。
open class Shape {
open val vertexCount: Int = 0
}
class Rectangle : Shape() {
override var vertexCount = 4
}
你也可以用一個 var
屬性覆蓋一個 val
屬性,但反之則不行。 這是允許的,因爲一個 val
屬性本質上聲明瞭一個 get
方法, 而將其覆蓋爲 var
只是在子類中額外聲明一個 set
方法.
請注意,你可以在主構造函數中使用 override 關鍵字作爲屬性聲明的一部分。
interface Shape {
val vertexCount: Int
}
class Rectangle(override val vertexCount: Int = 4) : Shape // 主構造函數中使用 override 關鍵字作爲屬性聲明的一部分
class Polygon : Shape {
override var vertexCount: Int = 0 // 以後可以設置爲任何數
}
7.調用超類實現
派生類中的代碼可以使用 super 關鍵字調用其超類的函數與屬性訪問器的實現: super. 調用父類方法或屬性;super@ 內部類中訪問外部類的超類 ; super<父類> 繼承多個超類 有相同的方法必須覆蓋這個成員提供自己的實現。
open class Foo { //超類
open fun f() { println("Foo.f()") }
open fun run(){ println("Foo.f()")}
open val x: Int get() = 1
}
interface Doo{ //接口
open fun run() { println("Doo.f()") }
}
class Bar : Foo(),Doo{
override val x: Int get() = 0
override fun f() {
println("Bar.f()")
super.f(); //調用父類方法或屬性
}
override fun run() { //一個類從它的直接超類繼承相同成員的多個實現, 它必須覆蓋這個成員並提供其自己的實現(也許用繼承來的其中之一)來消除歧義
super<Foo>.run()
super<Doo>.run()
}
inner class Baz { //內部類
public fun g() {
[email protected]() // 調用 Foo 實現的 f()
println([email protected]) // 使用 Foo 實現的 x 的 getter
}
}
public fun dosthing() { //使用於調用內部類方法。
Baz().g();
}
}
8.抽象類
類以及其中的某些成員可以聲明爲 abstract。 抽象成員在本類中可以不用實現。 需要注意的是,我們並不需要用 open
標註一個抽象類或者函數——因爲這不言而喻
我們可以用一個抽象成員覆蓋一個非抽象的開放成員 。注意:
抽象類不能用於創建實例,只能當作父類被其子類繼承。
abstract不能用於修飾局部變量,Kotlin中沒有抽象變量的說法;
使用abstract關鍵字修飾的方法必須被其子類重寫纔有意義
open class Polygon {
open fun draw() {}
}
abstract class Rectangle : Polygon() {
abstract override fun draw()
val a="1"
abstract val type: String
}
class person:Rectangle(){
override fun draw() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override val type: String
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
}
二.屬性
Kotlin 類中的屬性既可以用關鍵字 var 聲明爲可變的,也可以用關鍵字 val 聲明爲只讀的。
class Address {
var name: String = "Holmes, Sherlock"
var street: String = "Baker"
var city: String = "London"
var state: String? = null
var zip: String = "123456"
}
三.編譯期常量
如果只讀屬性的值在編譯期是已知的,那麼可以使用 const 修飾符將其標記爲編譯期常量。 這種屬性需要滿足以下要求:
- 位於頂層或者是 object 聲明 或 companion object 的一個成員
- 以
String
或原生類型值初始化 - 沒有自定義 getter
這些屬性可以用在註解中:
// companion object 修飾爲伴生對象,伴生對象在類中只能存在一個,類似於java中的靜態方法 Java 中使用類訪問靜態成員,靜態方法。
companion object {
const val C: Int = 0 //常量
/**main入口函數 **/
@JvmStatic
fun main(args: Array<String>) {
}
}
四.接口
Kotlin 的接口可以既包含抽象方法的聲明也包含實現。與抽象類不同的是,接口無法保存狀態。它可以有屬性但必須聲明爲抽象或提供訪問器實現。接口成員默認就是“open”的
interface MyInterface {
val prop: Int // 抽象的
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
實現多個接口時,可能會遇到同一方法繼承多個實現的問題。例如
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
上例中,接口 A 和 B 都定義了方法 foo() 和 bar()。 兩者都實現了 foo(), 但是隻有 B 實現了 bar() (bar() 在 A 中沒有標記爲抽象, 因爲沒有方法體時默認爲抽象)。因爲 C 是一個實現了 A 的具體類,所以必須要重寫 bar() 並實現這個抽象方法。
然而,如果我們從 A 和 B 派生 D,我們需要實現我們從多個接口繼承的所有方法,並指明 D 應該如何實現它們。這一規則既適用於繼承單個實現(bar())的方法也適用於繼承多個實現(foo())的方法。
五.修飾符
類的修飾符包括 classModifier 和_accessModifier_:
classModifier: 類屬性修飾符,標示類本身特性。
abstract // 抽象類
final // 類不可繼承,默認屬性
enum // 枚舉類
open // 類可繼承,類默認是final的
annotation // 註解類
accessModifier: 訪問權限修飾符
private // 僅在同一個文件中可見
protected // 同一個文件中或子類可見
public // 所有調用的地方都可見
internal // 同一個模塊中可見