1. 程式人生 > >Kotlin------類和物件(一)

Kotlin------類和物件(一)

和Java一樣,Kotlin中使用關鍵字class來宣告一個類。如下即是宣告一個最簡單的沒有任何屬性和方法的類

// 沒有任何屬性、方法的Invoice 類
class Invoice {}

一個完整的類宣告包含類名類頭(指定構造引數、構造方法等),類體(用大括號包裹的部分)。類頭和類體這兩個部分並非必要的,類頭和類體都是可選的; 如果一個類沒有類體,可以省略花括號。
class Invoice

建構函式

在 Kotlin 中的一個類可以有一個主建構函式和一個或多個次建構函式。主建構函式是類頭的一部分:它跟在類名(和可選的型別引數)後。


class Person constructor(firstName: String) {
}


如果主建構函式沒有任何註解或者可見性修飾符,可以省略這個 constructor 關鍵字。
class Person(firstName: String) {
}

主建構函式不能包含任何的程式碼。初始化的程式碼可以放到以 init 關鍵字作為字首的初始化塊(initializer blocks)中:

class Customer(p : Int) {
    init {
        println("Customer類初始化")
    }
}


次建構函式

二級建構函式,也稱為次級建構函式。關於二級建構函式,主要有以下幾點:

  1. 次級建構函式不能省略constructor關鍵字
  2. 當類擁有主建構函式時,任何一個二級建構函式都需要直接或間接通過另一個二級建構函式代理主建構函式
  3. 類中的一個建構函式代理另一個建構函式,需要使用關鍵字this

 類也可以宣告字首有 constructor次建構函式


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


class Person constructor(id: Int) {//(建構函式No.0)主建構函式
    var id = id//主建構函式初始化id
    var name = ""
    var age = 0
    //(建構函式No.1)直接代理主建構函式
    constructor(name: String, id: Int) : this(id) {
        this.name = name
    }
    //(建構函式No.2)代理了建構函式No.1,間接代理主建構函式
    constructor(name: String, age: Int, id: Int) : this(name, id) {
        this.age = age
    }
}

繼承

和所有的Java類都有一個共同的父類Object一樣且不支援同時繼承多個父類。Kotlin中所有的類都擁有一個共同的父類Any(但Any不是Object,不要搞錯)。Any相比Object其內部結構要簡單很多,僅有equals()、hashCode()、toString()三個抽象方法。

//預設情況下,在 Kotlin 中所有的類都是 final,
//抽象是面向物件程式設計的特徵之一,類本身,或類中的部分成員,都可以宣告為abstract的。抽象成員在類中不存在具體的實現。

open class Base(p: Int){
    init {
        println("基類")
    }

    //重寫
    //在基類中,使用fun宣告函式時,此函式預設為final修飾,不能被子類重寫。
    // 如果允許子類重寫該函式,那麼就要手動新增 open 修飾它, 子類重寫方法使用 override 關鍵詞:
    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關鍵字進行宣告,其中var為可變屬性,val為只讀屬性(相當於Java的final)。

class Student {
    var name = "名字" //名字屬性可變,用var
    val birthday = "1994-10-26" //生日屬性不可變,用val
}

像上面這樣就簡單的為Student類聲明瞭name和birthday兩個屬性,且在宣告屬性時進行了初始化,按照Kotlin的型別推斷特點,name和birthday就是屬於String型別(不知道型別推斷的同學可以翻閱前面的寫的文章)。現在我想為Student類新增一個age屬性,但是我並不想在宣告時進行初始化,用Java寫起來非常簡單即可實現
public class JavaStudent {
    private String name = "名字";
    private String birthday = "1994-10-26";
    private int age;//Java版的實現
}

按照Java的實現套路直接套入Kotlin你會發現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提供了延遲初始化的方式來解決初始化的問題,使用關鍵字lateinit即可,這樣就無需宣告abstract了。

 

可惜使用lateinit延遲初始化age之後,IDE依舊報錯,這次提示的內容是lateinit modifier is not allowed on primitive type properties。Kotlin並不支援對原生型別進行lateinit,為什麼呢?因為Kotlin會使用null來對每一個用lateinit修飾的屬性做初始化,而基礎型別是沒有null型別,所以無法使用lateinit。這點很好理解,就像可以把int型變數賦值為0,卻無法賦值為null一樣。所以這裡為了通過IDE的編譯,我們可以採用兩種方案,要麼還是直接在age宣告時進行初始化,要麼不用基礎型別來定義age。

class Student {
    var name = "名字" //名字屬性可變,用var
    val birthday = "1994-10-26" //生日屬性不可變,用val
    var age = 0 //直接使用0初始化age,age為Int型
    lateinit var ageStr: String //String不是基礎型別,可以使用lateinit初始化
}

建立物件

呼叫類的構造器,呼叫方式和使用普通函式一樣:

val person = Student ()


注意:Kotlin 沒有 new 關鍵字。