類聲明
和Java一樣,Kotlin中使用關(guān)鍵字class來聲明一個類。如下即是聲明一個最簡單的沒有任何屬性和方法的類
// 沒有任何屬性、方法的Invoice 類
class Invoice {}
一個完整的類聲明包含類名,類頭(指定構(gòu)造參數(shù)、構(gòu)造方法等),類體(用大括號包裹的部分)。類頭和類體這兩個部分并非必要的,類頭和類體都是可選的; 如果一個類沒有類體,可以省略花括號。
class Invoice
構(gòu)造函數(shù)
在 Kotlin 中的一個類可以有一個主構(gòu)造函數(shù)和一個或多個次構(gòu)造函數(shù)。主構(gòu)造函數(shù)是類頭的一部分:它跟在類名(和可選的類型參數(shù))后。
class Person constructor(firstName: String) {
}
如果主構(gòu)造函數(shù)沒有任何注解或者可見性修飾符,可以省略這個 constructor 關(guān)鍵字。
class Person(firstName: String) {
}
主構(gòu)造函數(shù)不能包含任何的代碼。初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊(initializer blocks)中:
class Customer(p : Int) {
init {
println("Customer類初始化")
}
}
次構(gòu)造函數(shù)
二級構(gòu)造函數(shù),也稱為次級構(gòu)造函數(shù)。關(guān)于二級構(gòu)造函數(shù),主要有以下幾點:
次級構(gòu)造函數(shù)不能省略constructor關(guān)鍵字;
當(dāng)類擁有主構(gòu)造函數(shù)時,任何一個二級構(gòu)造函數(shù)都需要直接或間接通過另一個二級構(gòu)造函數(shù)代理主構(gòu)造函數(shù);
類中的一個構(gòu)造函數(shù)代理另一個構(gòu)造函數(shù),需要使用關(guān)鍵字this;
類也可以聲明前綴有 constructor的次構(gòu)造函數(shù):
class Person {
constructor(parent: Person) {
parent.children.add(this )
}
}
class Person constructor(id: Int) {//(構(gòu)造函數(shù)No.0)主構(gòu)造函數(shù)
var id = id//主構(gòu)造函數(shù)初始化id
var name = ""
var age = 0
//(構(gòu)造函數(shù)No.1)直接代理主構(gòu)造函數(shù)
constructor(name: String, id: Int) : this(id) {
this.name = name
}
//(構(gòu)造函數(shù)No.2)代理了構(gòu)造函數(shù)No.1,間接代理主構(gòu)造函數(shù)
constructor(name: String, age: Int, id: Int) : this(name, id) {
this.age = age
}
}
繼承
和所有的Java類都有一個共同的父類Object一樣且不支持同時繼承多個父類。Kotlin中所有的類都擁有一個共同的父類Any(但Any不是Object,不要搞錯)。Any相比Object其內(nèi)部結(jié)構(gòu)要簡單很多,僅有equals()、hashCode()、toString()三個抽象方法。
//默認(rèn)情況下,在 Kotlin 中所有的類都是 final,
//抽象是面向?qū)ο缶幊痰奶卣髦唬惐旧恚蝾愔械牟糠殖蓡T,都可以聲明為abstract的。抽象成員在類中不存在具體的實現(xiàn)。
open class Base(p: Int){
init {
println("基類")
}
//重寫
//在基類中,使用fun聲明函數(shù)時,此函數(shù)默認(rèn)為final修飾,不能被子類重寫。
// 如果允許子類重寫該函數(shù),那么就要手動添加 open 修飾它, 子類重寫方法使用 override 關(guān)鍵詞:
open fun sdutent() {
println("基類方法")
}
}
class Customer(p : Int): Base(p) {
init {
println("Customer類")
}
constructor(p: Int,n: String):this(p){
println("$p is n= $n")
}
override fun sdutent() {
super.sdutent()
println("重寫基類的方法")
}
}
屬性和賦值
在聲明一個最簡單的空殼類之后,我們來為它增加一些類屬性。Kotlin中類的屬性可以用var或者val關(guān)鍵字進行聲明,其中var為可變屬性,val為只讀屬性(相當(dāng)于Java的final)。
class Student {
var name = "名字" //名字屬性可變,用var
val birthday = "1994-10-26" //生日屬性不可變,用val
}
像上面這樣就簡單的為Student類聲明了name和birthday兩個屬性,且在聲明屬性時進行了初始化,按照Kotlin的類型推斷特點,name和birthday就是屬于String類型(不知道類型推斷的同學(xué)可以翻閱前面的寫的文章)。現(xiàn)在我想為Student類添加一個age屬性,但是我并不想在聲明時進行初始化,用Java寫起來非常簡單即可實現(xiàn)
public class JavaStudent {
private String name = "名字";
private String birthday = "1994-10-26";
private int age;//Java版的實現(xiàn)
}
按照J(rèn)ava的實現(xiàn)套路直接套入Kotlin你會發(fā)現(xiàn)IDE直接報錯并提示property must be initialized or be abstract。
按照提示我們必須把類和字段都聲明為abstract才可以通過編譯。
abstract class Student {
var name = "名字" //名字屬性可變,用var
val birthday = "1994-10-26" //生日屬性不可變,用val
abstract var age: Int
}
這樣未免太過麻煩,而且理解起來也非常奇怪。Kotlin提供了延遲初始化的方式來解決初始化的問題,使用關(guān)鍵字lateinit即可,這樣就無需聲明abstract了。
可惜使用lateinit延遲初始化age之后,IDE依舊報錯,這次提示的內(nèi)容是lateinit modifier is not allowed on primitive type properties。Kotlin并不支持對原生類型進行l(wèi)ateinit,為什么呢?因為Kotlin會使用null來對每一個用lateinit修飾的屬性做初始化,而基礎(chǔ)類型是沒有null類型,所以無法使用lateinit。這點很好理解,就像可以把int型變量賦值為0,卻無法賦值為null一樣。所以這里為了通過IDE的編譯,我們可以采用兩種方案,要么還是直接在age聲明時進行初始化,要么不用基礎(chǔ)類型來定義age。
class Student {
var name = "名字" //名字屬性可變,用var
val birthday = "1994-10-26" //生日屬性不可變,用val
var age = 0 //直接使用0初始化age,age為Int型
lateinit var ageStr: String //String不是基礎(chǔ)類型,可以使用lateinit初始化
}
創(chuàng)建對象
調(diào)用類的構(gòu)造器,調(diào)用方式和使用普通函數(shù)一樣:
val person = Student ()