Kotlin 的屬性(Properties)看起來與 Java 的物件屬性相似,但它們實際上代表著不同的概念。
// Kotlin 屬性
var name: String? = null
// Java 欄位
String name = null;
儘管可以用相同的方式使用,把來資料記在物件上,但我們需要記住 Kotlin 的 properties 具有更多的能力
var name: String? = null
get() = field?.uppercase(Locale.getDefault())
set(value) {
if (!value.isNullOrBlank()) {
field = value
}
}
在上例中,我們使用了 field 這個參數。這是指向讓我們在此屬性中資料的後置欄位的引用。這個 field 後置欄位是預設生成的,因為設定器 (setter) 和取值器的 (getter) 預設實現會使用它們。我們也可以實現不使用它們的自定義訪問器,這樣的情況下屬性根本不會有欄位值。例如,Kotlin 屬性可以僅使用取值器來定義唯讀屬性 val:
val fullName: String
get() = "$name $surname"
對於可讀寫的屬性 var,我們可以通過定義取值器和設定器來製作屬性。這種屬性被稱為衍生屬性,它們並不少見。它們是 Kotlin 中所有屬性預設封裝的主要原因。想像一下,你必須在你的類型中保存一個日期,你使用了來自 Java stdlib 的 Date。然後,由於某種原因,該類型不能再操作此類型的屬性。也許是因為序列化問題,或者是因為你將此類型提升到了一個共同的模組。問題是這個屬性已經在整個專案中被引用了。
使用 Kotlin,這不再是問題,因為你可以將數據移到另一個屬性 millis 中,並修改日期屬性不保存數據,而是包裝/解包那個其他屬性。
var date: Date
get() = Date(millis)
set(value) {
millis = value.time
}
所以屬性其實不需要欄位。從概念上講,它們代表取值器(val 的取值器,var 的取值器和設定器)。這就是為什麼我們可以在介面定義屬性,其實是代表著取值器 + 設定器(var)
interface Person {
val name: String
}
這意味著此介面承諾擁有一個取值器。我們還可以覆蓋屬性:
open class Supercomputer {
open val theAnswer: Long = 42
}
class AppleComputer : Supercomputer() {
override val theAnswer: Long = 1_800_275_2273
}
由於同樣的原因,我們可以委派屬性:
val db: Database by lazy { connectToDb() }
因為屬性本質上是函數,所以我們也可以製作擴展屬性:
val Context.preferences: SharedPreferences
get() = PreferenceManager
.getDefaultSharedPreferences(this)
val Context.inflater: LayoutInflater
get() = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val Context.notificationManager: NotificationManager
get() = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
如你所見,屬性代表取值器,而不是欄位。這樣,它們可以代替某些函數,但我們應該小心我們如何使用它們。不應該使用屬性來代表高度運算的行為,如下例所示:
// 別這麼做!
val Tree<Int>.sum: Int
get() = when (this) {
is Leaf -> value
is Node -> left.sum + right.sum
}
此處 sum 屬性遍歷所有元素,因此它代表演算法行為。因此,此屬性會產生誤導:對於大集合,找到答案在計算上可能會很沉重,這對於取值器來說根本不符合預期。這不應該是一個屬性,這應該是一個函數:
fun Tree<Int>.sum(): Int = when (this) {
is Leaf -> value
is Node -> left.sum() + right.sum()
}
一般規則是,我們應該僅使用屬性它們來代表或設定狀態,不應該涉及其他邏輯
今天孩子們上了第二首 The first take - I DO