提示:本文爲作者閱讀Kotlin中文站學習筆記,建議讀者移步Kotlin中文站完整學習。
屬性
Kotlin的類可以有屬性。我們可以使用var關鍵字聲明一個可變的屬性,或val關鍵字聲明一個只讀的屬性。
class R{
var a:String=""//var 聲明一個可變的屬性
val b:String=""//val 聲明一個只讀的屬性
}
聲明一個屬性的完整語法是:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
初始化其(initializer),getter/setter方法都是可選的,屬性類型如果可以從初始化器或getter方法中判斷出,也可以省略。
var c:String
get() = ""
set(value) {
c=value
}
val d=1//Int 默認getter實現,類型可以從初始化器中判斷出來,可以省略
一個只讀屬性的語法和一個可變的屬性的語法有兩方面的不同:1、只讀屬性的用 val開始代替var 2、只讀屬性不允許 setter。
如果你需要改變一個訪問器的可見性或者對其註解,但是不需要改變默認的實現, 你可以定義訪問器而不定義其實現:
private var a:String=""//var 聲明一個可變的屬性
private get//改變訪問器的可變性,不改變其默認實現
幕後字段
Kotlin 中類不能有字段。然而,當使用自定義訪問器時,有時有一個幕後字段(backing field)有時是必要的。爲此 Kotlin 提供一個自動幕後字段,它可通過使用 field 標識符訪問。
var c:String=""// 此初始器值直接寫入到幕後字段
set(value) {
field=value
}
field 標識符只能用在屬性的訪問器內。
如果屬性至少一個訪問器使用默認實現,或者自定義訪問器通過 field 引用幕後字段,將會爲該屬性生成一個幕後字段。下面的情況屬性就沒有幕後字段:
//c屬性沒有幕後字段,無法初始化
var c:String
get() = ""
set(value) {
c=value
}
//c屬性有幕後字段,必須初始化
var c:String=""
get() = ""
set(value) {
field=value//自定義訪問器通過field訪問幕後字段
}
幕後屬性
如果你的需求不符合這套“隱式的幕後字段”方案,那麼總可以使用 幕後屬性(backing property):
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // 類型參數已推斷出
}
return _table ?: throw AssertionError("Set to null by another thread")
}
從各方面看,這正是與 Java 相同的方式。因爲通過默認 getter 和 setter 訪問私有屬性會被優化,所以不會引入函數調用開銷。
編譯期常量
已知值的屬性可以使用 const 修飾符標記爲 編譯期常量。 這些屬性需要滿足以下要求:
- 位於頂層或者是 object 的一個成員
- 用 String 或原生類型 值初始化
- 沒有自定義 getter
這些屬性可以用在註解中:
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }
延遲初始化屬性
一般地,屬性聲明爲非空類型必須在構造函數中初始化。 然而,這經常不方便。例如:屬性可以通過依賴注入來初始化, 或者在單元測試的 setup 方法中初始化。 這種情況下,你不能在構造函數內提供一個非空初始器。 但你仍然想在類體中引用該屬性時避免空檢查。
爲處理這種情況,你可以用 lateinit 修飾符標記該屬性:
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 直接解引用
}
}
該修飾符只能用於在類體中(不是在主構造函數中)聲明的 var 屬性,並且僅當該屬性沒有自定義 getter 或 setter 時。該屬性必須是非空類型,並且不能是原生類型。
在初始化前訪問一個 lateinit 屬性會拋出一個特定異常,該異常明確標識該屬性被訪問及它沒有初始化的事實。