1、聲明屬性
- Kotlin 類中的屬性既可以用關鍵字
var
聲明為可變的忿项,也可以用關鍵字val
聲明為只讀的。
class Address {
var name: String = ""http://地址名稱
var street: String = ""http://街道
var city: String =""http://城市名稱
var state: String? ="" //狀態(tài)可以為空null
var zip: String =""http://郵政編碼
}
- 要使用一個屬性,只要用名稱引用它即可算撮,就像 Java 中的字段:
fun copyAddress(address: Address): Address {
val result = Address() // Kotlin 中沒有“new”關鍵字
result.name = address.name // 將調用訪問器
result.street = address.street
// ……
return result
}
-
2、 Getters 與 Setters
*聲明一個屬性的完整語法是
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
- 其初始器(initializer)县昂、getter 和 setter 都是可選的肮柜。屬性類型如果可以從初始器 (或者從其 getter 返回值,如下文所示)中推斷出來倒彰,也可以省略审洞。
var allByDefault: Int? // 錯誤:需要顯式初始化器,隱含默認 getter 和 setter
var initialized = 1 // 類型 Int待讳、默認 getter 和 setter
- 一個只讀屬性的語法和一個可變的屬性的語法有兩方面的不同:1芒澜、只讀屬性的用 val開始代替var 2、只讀屬性不允許 setter
val simple: Int? // 類型 Int创淡、默認 getter痴晦、必須在構造函數中初始化
val inferredType = 1 // 類型 Int 、默認 getter
- 我們可以為屬性定義自定義的訪問器琳彩。如果我們定義了一個自定義的 getter誊酌,那么每次訪問該屬性時都會調用它 (這讓我們可以實現(xiàn)計算出的屬性)。以下是一個自定義 getter 的示例:
val isEmpty: Boolean
get() = this.size == 0
- 如果我們定義了一個自定義的 setter露乏,那么每次給屬性賦值時都會調用它碧浊。一個自定義的 setter 如下所示
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // 解析字符串并賦值給其他屬性
}
- 按照慣例,setter 參數的名稱是 value施无,但是如果你喜歡你可以選擇一個不同的名稱辉词。自 Kotlin 1.1 起,如果可以從 getter 推斷出屬性類型猾骡,則可以省略它
val isEmpty get() = this.size == 0 // 具有類型 Boolean
- 如果你需要改變一個訪問器的可見性或者對其注解瑞躺,但是不需要改變默認的實現(xiàn), 你可以定義訪問器而不定義其實現(xiàn):
var setterVisibility: String = "abc"
private set // 此 setter 是私有的并且有默認實現(xiàn)
var setterWithAnnotation: Any? = null
@Inject set // 用 Inject 注解此 setter
3兴想、幕后字段
- 在 Kotlin 類中不能直接聲明字段幢哨。然而,當一個屬性需要一個幕后字段時嫂便,Kotlin 會自動提供捞镰。這個幕后字段可以使用field標識符在訪問器中引用:
var counter = 0 // 注意:這個初始器直接為幕后字段賦值
set(value) {
if (value >= 0) field = value
}
- field 標識符只能用在屬性的訪問器內,如果屬性至少一個訪問器使用默認實現(xiàn),或者自定義訪問器通過 field 引用幕后字段,將會為該屬性生成一個幕后字段岸售。例如践樱,下面的情況下, 就沒有幕后字段
val isEmpty: Boolean
get() = this.size == 0
4凸丸、幕后屬性
- 如果你的需求不符合這套“隱式的幕后字段”方案拷邢,那么總可以使用 幕后屬性(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 訪問私有屬性會被優(yōu)化瞭稼,所以不會引入函數調用開銷。
5腻惠、編譯期常量
已知值的屬性可以使用 const 修飾符標記為 編譯期常量环肘。 這些屬性需要滿足以下要求:
- 位于頂層或者是 object 聲明 或 companion object 的一個成員* 以
String
或原生類型值初始化 - 沒有自定義 getter
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }
6、延遲初始化屬性與變量
- 一般地集灌,屬性聲明為非空類型必須在構造函數中初始化悔雹。 然而,這經常不方便欣喧。例如:屬性可以通過依賴注入來初始化荠商, 或者在單元測試的 setup 方法中初始化。 這種情況下续誉,你不能在構造函數內提供一個非空初始器。 但你仍然想在類體中引用該屬性時避免空檢查初肉。
- 為處理這種情況酷鸦,你可以用
lateinit
修飾符標記該屬性
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 直接解引用
}
}
1、該修飾符只能用于在類體中的屬性(不是在主構造函數中聲明的 var 屬性牙咏,并且僅當該屬性沒有自定義 getter 或 setter 時)臼隔,而自 Kotlin 1.2 起,也用于頂層屬性與局部變量妄壶。該屬性或變量必須為非空類型摔握,并且不能是原生類型。
2丁寄、在初始化前訪問一個 lateinit 屬性會拋出一個特定異常氨淌,該異常明確標識該屬性被訪問及它沒有初始化的事實。
3伊磺、檢測一個 lateinit var 是否已初始化(自 1.2 起)
- 要檢測一個
lateinit var
是否已經初始化過盛正,請在該屬性的引用上使用.isInitialized
:
if (foo::bar.isInitialized) {
println(foo.bar)
}
- 此檢測僅對可詞法級訪問的屬性可用,即聲明位于同一個類型內屑埋、位于其中一個外圍類型中或者位于相同文件的頂層的屬性豪筝。
7、覆蓋屬性
參見覆蓋屬性
8、委托屬性
最常見的一類屬性就是簡單地從幕后字段中讀刃隆(以及可能的寫入)敲街。 另一方面,使用自定義 getter 和 setter 可以實現(xiàn)屬性的任何行為严望。 介于兩者之間多艇,屬性如何工作有一些常見的模式。一些例子:惰性值著蟹、 通過鍵值從映射讀取墩蔓、訪問數據庫、訪問時通知偵聽器等等萧豆。
這些常見行為可以通過使用委托屬性實現(xiàn)為庫奸披。