前言
本文是基礎,需要通篇看。
除了文字版本,也有Xmind版本 github地址
同樣也帶着幾個問題來看:
① 幕後字段與幕後屬性的區別
② val var什麼區別
③ field字段什麼時候不會有
④ 屬性延遲初始化怎麼實現?
⑤ 什麼是編譯期常量
本文目錄如下
- 定義
- getter和setter
- var
- val
- getter和setter方法的權限
- 注意
- 幕後字段
- 什麼時候沒有field字段?
- 幕後屬性
- 定義
- 對於 JVM 平臺
- 幕後字段與幕後屬性的區別
- 編譯期常量
- 延遲初始化屬性與變量
- 解決辦法
- 適用範圍
- 注意
- 檢測一個 lateinit var 是否已初始化(自 1.2 起)
- 覆蓋屬性
- 委託屬性
定義
val var是不是有一股JS的味道。
屬性定義有兩種
- var 可變
- val 不可變
屬性引用
myInstance.myVar
getter和setter
格式是這樣的
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
getter 和 setter 都是可選
有幾個規則。
- val是不可變,so沒有setter
var
可變的可賦值的變量
var allByDefault: Int? // 錯誤: 需要一個初始化語句, 默認實現了 getter 和 setter 方法
var initialized = 1 // 類型爲 Int, 默認實現了 getter 和 setter
val
不可變的不可賦值的變量
val simple: Int? // 類型爲 Int ,默認實現 getter ,但必須在構造函數中初始化
val inferredType = 1 // 類型爲 Int 類型,默認實現 getter
範例一: 修改了get方法
var lastName: String = "zhang"
get() = field.toUpperCase() // 將變量賦值後轉換爲大寫
set
範例二: 修改了set方法
var no: Int = 100
get() = field // 後端變量
set(value) {
if (value < 10) { // 如果傳入的值小於 10 返回該值
field = value
} else {
field = -1 // 如果傳入的值大於等於 10 返回 -1
}
}
getter和setter方法的權限
setter方法:支持加屬性 private protected 等
getter方法:的權限跟所處的變量一致
注意
field屬性的作用域:
- 僅僅存在於當前屬性的setter/getter方法中
- 就像當前屬性的影子一樣。
- 它是自動生成
範例三
class Person {
var lastName: String = "zhang"
get() = field.toUpperCase() // 將變量賦值後轉換爲大寫
set
var color: String = "#ff0000"
set(value){ field = value }
get() = field
var number : Int = 100
var no: Int = 100
get() = field // 後端變量
set(value) {
if (value < 10) { // 如果傳入的值小於 10 返回該值
field = value
} else {
field = -1 // 如果傳入的值大於等於 10 返回 -1
}
}
var heiht: Float = 145.4f
private set
}
fun main(args: Array<String>) {
var person: Person = Person()
person.lastName = "wang"
println("lastName:${person.lastName}")
person.no = 9
println("no:${person.no}")
println("no:${person.number}")
person.color = ("#ffffff")
println("no:${person.color}")
println("no:${person.heiht}")
}
輸出
lastName:WANG
no:9
no:100
no:#ffffff
no:145.4
幕後字段
用field標識符
在訪問器中引用
當一個屬性需要一個幕後字段時,Kotlin 會自動提供
var counter = 0 // 注意:這個初始器直接爲幕後字段賦值
set(value) {
if (value >= 0) field = value
}
只能用在屬性的訪問器內
什麼時候沒有field字段?
field字段是需要特定的條件下才能產生的。部分情況不會產生。
- 不使用默認實現
- 且不通過 field 引用幕後字段
比如以下這種情況
val isEmpty: Boolean
get() = this.size == 0
幕後屬性
定義
幕後屬性是我們自己定義的,一般用於這種情況
- 對外表現爲只能讀,不能寫
- 對內表現可以任意讀寫
相當於,一個變量即是 val 又是var,java可以通過函數實現
範例
class Demo{
val size get() = _size
private var _size:Int = 0
fun rise() {
_size = _size + 1
}
}
fun main(args: Array<String>) {
val demo = Demo()
println(demo.size)
demo.rise()
println(demo.size)
demo.rise()
println(demo.size)
}
輸出
0
1
2
對於 JVM 平臺
通過默認 getter 和 setter 訪問私有屬性會被優化
不會引入函數調用開銷
幕後字段與幕後屬性的區別
幕後字段:Kotlin內置提供給我們的
幕後屬性:是我們設計類屬性時的一種實現方法而已
編譯期常量
使用 const 修飾符標記爲 編譯期常量
使用條件
- 位於頂層或者是 object 聲明 或 companion object 的一個成員
- 以 String 或原生類型值初始化
- 沒有自定義 getter
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
與java一樣
常量可以用在註解中
延遲初始化屬性與變量
一般地,屬性聲明爲非空類型必須在構造函數中初始化
但是,你是通過註解,或者某setup函數來初始化的
你不能在構造函數內提供一個非空初始器
仍然想在類體中引用該屬性時避免空檢測
解決辦法
用 lateinit 修飾符標記該屬性
適用範圍
- 非空類型
- 非原生類型
注意
在初始化前訪問一個 lateinit 屬性會拋出一個特定異常,
該異常明確標識該屬性被訪問及它沒有初始化的事實。
檢測一個 lateinit var 是否已初始化(自 1.2 起)
用 .isInitialized
if (foo::bar.isInitialized) {
println(foo.bar)
}
僅對可詞法級訪問的屬性
覆蓋屬性
可以參考 《類篇》
委託屬性
即delegate
用到了關鍵字 by
範例
class Example {
var p: String by Delegate()
}
後續我們會講到