Kotlin學習系列之:數據類(data class)和密封類(sealed class)

一、數據類(data class)

    在介紹數據類之前,我們先來看看這樣一段代碼:

class Student(val name: String, var age: Int)

fun main(args: Array<String>) {

    val student = Student("David", 12)
    println(student)
}

此時會打印:
com.xlh.test.data.Student@49476842

大家都知道,這樣直接打印student,會導致Student類的toString方法得到調用,最終打印到控制檯的結果就是toString方法的返回結果。而Object類中的toString方法的實現(這裏你可能產生疑問,Kotlin中的超級父類是Any類型,而不是Object類型,它倆的關係參看這篇博客):

所以就會出現前面的輸出結果。

現在我們在類的聲明前添加data關鍵字:

data class Student(val name: String, var age: Int)

其他不變,再看輸出:

發生變化了,那就說明添加了data關鍵字後,Student類toString方法被重寫了,並且形式爲(屬性名=屬性值...),逗號分隔。實際上此時Student類就是一個數據類。

1. 如何定義數據類

在類的聲明前添加data關鍵字,即可將一個類定義成數據類。

2. 數據類需要滿足的要求
a) 主構造器至少有一個參數
b) 主構造器中的參數都需要使用var、val修飾

c) 數據類不能是abstract、open、sealed和inner的

3. 反編譯,查看類的結構

可以看到,一旦添加了data關鍵字,類的結構會發生變化,添加了很多方法,這就和擴展不一樣了。我們來總結一下一共添加了哪些方法:

 

  • setter/getter
  • toString()
  • equals()
  • hashCode()
  • componentN()
  • copy()

前面三個方法都是kotlin.Any類中的定義的,在數據類中會被重寫。接下來我們來介紹一下後面兩個稍微陌生的方法:

 

  • 如何理解copy()方法:儘管主構造中聲明的屬性既可以被定義爲var、val,但是最好的方式就是val,即爲只讀屬性。聲明爲只讀屬性意味着一旦對象被創建後,它就會保持它的初始狀態,特別是在多線程環境下不用擔心它的值被其他線程而修改。假設把這種習慣或者說編碼風格叫做一種約定,那麼在這種背景下隨之而來就會有一個問題:如果我們確實想修改只讀屬性的值,那麼該怎麼辦?copy()方法就可以解決。
val copyStudent = student.copy(name = "xlh", age = 12)
  
println(copyStudent)

      打印:

    這樣就會創建一個新的對象並且修改了它的只讀屬性然後返回。注意:
    i. 原來的Student對象的屬性值並沒有改變

    ii. 參數的傳遞問題:可以不傳,表示不修改屬性值;如果傳遞的參數不是按照聲明的順序,那麼必須使用有名參數的形式來調用,其他的情況下任意。 

總結copy方法的作用:就是創建一個當前對象的一份拷貝,並且在copy的過程中可以選擇性改變拷貝對象的屬性值,而原來對象的屬性值不會改變。注意這裏是淺拷貝。

 

  • 理解componentN方法:能夠保證數據類可以使用解構聲明(destructuring declarations)。
val (name, age) = student
println("$name, $age")

此時就可以輸出:

4. 關於data class最後再補充一點:

    在第3點中列出的方法裏,只針對定義在主構造函數中的屬性,如果你定義了一個屬性:

data class Student(val name: String, var age: Int) {

    var address = "beijing"
}

這個address屬性就不會被考慮。

二、密封類(sealed class)
1. 語法含義:密封類的子類要該密封類放置在同一個文件中。
2. 示例:
SealedTest.kt

sealed class Animal

class Dog : Animal() {

    fun bark() {
        println("wangwangwang")
    }
}

class Cat : Animal() {

    fun miao() {
        println("miaomiaomiao")
    }
}

fun sayHello(animal: Animal) {

    when (animal) {
        is Dog -> animal.bark()	//Smart Cast
        is Cat -> animal.miao()
	//Don’t need else
    }
}

fun main(args: Array<String>){
    sayHello(Dog())
    sayHello(Cat())
}

2. 密封類從某種程度上可以說子類的枚舉化,從類的層次上進行了限制。

3. 密封類的子類的子類可以定義在任何地方,並不需要和密封類定義在同一個文件中。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章