我們會經常創建一些只用來保存數據的類。在這種類中一些標準功能和效用的函數通常可以根據數據機械地推導出來。在Kotlin中,它被稱作數據類,並被標記爲data
:
data class User(val name: String, val age: Int)
編譯器會根據主構造函數中所聲明的所有屬性自動推導出下列成員:
equls()
/hashcode()
對- 打印
"User(name=John, age=42)"
格式的toString()
方法 componentN(.)
函數按聲明順序對應於所有屬性copy()
函數
其中componentN(.)函數會在後面的章節詳細講解,這裏暫時不管
爲了確保生成的代碼的一致性和有意義的行爲,數據類必須滿足以下要求:
- 主構造函數至少有一個參數
- 所有主構造函數的參數必須用
val
或var
標記 - 數據類不能爲
abstract
,open
,sealed
或inner
- (Kotlin 1.1之前)數據類只能實現接口
此外,成員的生成遵循成員繼承的一些規則:
- 如果數據類中已經顯示實現了equals(),hashCode() 或 toString() 方法,或者在其父類中已經final實現了這些方法,那麼已實現的方法將不會再生成,而是使用已實現的方法
- 如果超類型具有
open
的componentN()
函數並且返回兼容的類型, 那麼會爲數據類生成相應的函數,並覆蓋超類的實現。如果超類型的這些函數由於簽名不兼容或者是final
而導致無法覆蓋,那麼會報錯; componentN()
和copy()
方法不支持顯示實現
從Kotlin 1.1起,數據類可以繼承其它類
在JVM平臺上,如果生成的類需要無參構造函數,所有屬性都要指定默認值。
data class User(val name: String = "", val age: Int = 0)
在類體中聲明的屬性
注意編譯器只會爲主構造函數中的屬性自動生成函數,在類體中聲明的屬性將被排除在外。
data class Person(val name: String) {
var age: Int = 0
}
上面這個Person
類,只有屬性name
會被使用在toString()
,equals()
,hashCode()
和 copy()
的實現中,並且只會有一個component
函數component1()
。當兩個Person
對象的age
值不同時,它們仍然是equal
的,因爲默認的equals()
方法不會考慮age
屬性,只考慮主構造函數中的屬性。
@Test
fun testEquals(): Unit {
val person1 = Person("crx")
val person2 = Person("crx")
person1.age = 2
person2.age = 6
assertTrue(person1.equals(person2))
}
上面的測試代碼不會報錯
複製
通常我們需要複製一個對象,只改變其某些屬性,其它屬性保持不變。copy()
方法就是用來做這個的。對於上面的User類,其實現方法如下:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
它允許我們這樣寫:
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
數據類和解構聲明
數據類生成的component
函數允許它們使用解構聲明。
val jane = User("Jane", 35)
val(name, age) = jane
print("$name, $age years of age")
會打印出:Jane, 35 years of age
解構聲明將在後面的章節細講
標準數據類
Kotlin標準庫中提供了Pair
和Triple
方法。在大多數情況下,使用命名的數據類是更好的設計選擇,因爲提供有意義的名字和屬性會讓代碼更具可讀性。
Pair
使用方法如下:
val(name, age) = Pair("Jane", 23)
print("$name, $age years of age")
打印結果和上面的代碼一樣。
Triple
使用方法和Pair
相似,接收三個參數。