簡介
本篇博客主要是介紹Kotlin語法中的【類的屬性和字段】相關的知識,幫助各位更快的掌握Kotlin,如果有疏漏或者錯誤,請在留言中指正,謝謝。 系列彙總地址
基礎知識
定義
在講解之前我感覺有很多人根本不清楚什麼是屬性,什麼又是字段,我們先簡單說明一下。
簡單理解:
字段,通常叫做類成員或者類成員變量,理解爲”數據成員”,用來承載數據。
屬性,通常可以理解爲set和get方法。其屬名性時根據get和set方法名得出的,規則是:去掉get或set後其剩餘的字符串,屬性大多是對字段的封裝,限制其訪問和寫入。
具體說明(以java爲例):
字段,在類中定義的成員變量。
public class A{ private String s = "123"; }
我們可以描述爲A類中有個s字段
屬性,只侷限於類中方法的聲明,並不與類中其他成員相關。
void setA(String s){} String getA(){return s}
當一個類中擁有這樣一對方法時,我們可以說,這個類中擁有一個可讀寫的a屬性(注意是小寫a)。如果去掉了
set
的方法,則是可讀屬性,反之亦然。
總結一波:通過上面的介紹我們瞭解了什麼是屬性以及什麼是字段,在java
和Kotlin
中其含義是一致的。
屬性和字段
聲明屬性
對於Kotlin的類可以有屬性。我們之前也說過可以通過var
聲明可變屬性,val
聲明只讀屬性,或許你會問了,爲什麼不是叫字段而是叫屬性呢?因爲Kotlin
類中聲明的變量,都會提供默認的get
、set
(val沒有該方法)方法,所以聲明的都是屬性。Kotlin
中沒有字段,只有幕後字段(backing filed)。
我們聲明的時候大都採用下面的形式:
class People {
var name: String? = null
var address: String = "地球"
var age: Int? = null
}
你或許會說,屬性是有get、set方法的(不僅限於此),那Kotlin自己實現的怎麼用呢?
var people=People() //聲明實例,不需要new
people.name //直接使用,內部會調用訪問方法
上面我們看到使用起來還是比較簡單的。類似於我們java
中聲明瞭私有變量,然後提供了set、get
方法,到達屬性的目的。
Getters和Setters
聲明一個屬性的完整語法如下:
【屬性修飾符(var、val)】+【屬性名稱】+ 【:】 + 【類型】 = 【初始化】
【gettter】
【setter】
對於【初始化】和【getter】和【setter】都是可選的,如果通過【初始化】的值或者【getter】可以推斷出類型,則【類型】也可以省略。
屬性通過var
和val
去聲明得到只讀屬性和可變屬性,那他們的區別究竟是什麼呢?
只讀屬性和可變屬性的區別:
只讀屬性使用
val
聲明,可變屬性使用var
聲明只讀屬性不允許
setter
看到此處你或許會感嘆Kotlin
的厲害之處,省了不知多少時間,但有些人或許會感嘆了,如果我想自己定義屬性的訪問方法又怎麼弄呢?像java
再自定義方法嗎?會不會和默認的setter
或者getter
衝突呢?對於疑問我們一一解答。
自定義Getters和Setters
編寫Getters
和Setters
非常像一般的不同方法,在屬性聲明內部,舉例:
Getters方法:
var name: String? = null //聲明name屬性
get() {//重寫get方法
return "hhh"
}
var people=People()
people.name
此處的name
的值便是hhh
,且無論name
設置成什麼值。
Setters方法:
set(value) {//錯誤寫法
name=value //1)
}
在此不知道有沒有人看出不對的地方,上面 1) 處會導致循環調用,爲什麼呢?當你對屬性賦值的時候就會調用set方法,當你獲取屬性的值得時候就會使用get方法。所以上面會一直循環調用set方法。
下面我們看看正確的怎麼寫:
set(value) {
field=value
}
看完上面的代碼,你應該有兩個疑問,1.value 是什麼鬼,field 又是什麼鬼。。。
好,我們說明一下:
value
是setter
的參數,其類型同於屬性的類型,不爽你也可以換個其他名字。。field
就是我們之前說的幕後字段,用於將真正的值賦值給屬性,而不會導致循環調用。它只能在屬性的訪問器中使用。這個也是可選項,有的時候必須(比如上面的Setter),有的時候不是必須(比如上面的Getter)。
如果上面的幕後字段仍然不能滿足你…還有更猛的,幕後屬性。
private var _table: HashMap<String, String>? = null//私有屬性
var table: HashMap<String, String>? = null
get() {
if (_table == null) {
_table = HashMap<String, String>()
}
return _table //返回私有屬性
}
上面的代碼需要特殊說明一下,當屬性被定義爲private
後其Getter
和Setter
,都是私有的,外部都不可以訪問也就是說 person._table
是不允許的。也就進行了隱藏。又因爲默認的Setter
和Getter
調用私有屬性會被進行優化,所以不會引入函數調用開銷。
編譯期常量
在kotlin
中已知值得屬性可以使用const
標記爲編譯期常量。
它需要滿足以下條件:
- 使用
val
聲明的常量 - 位於頂層或者
object
的一個成員 - 用
String
或者原生類型值初始化 - 沒有自定義
Getter
延遲初始化屬性
對於非空屬性,在聲明時必須對其進行初始化,如果想進行延遲初始化,可以使用lateinit
標記,代碼舉例:
lateinit var name: String
需要注意以下幾點:
- 該修飾符只能用於類體中不是方法中的屬性
- 沒有自定義
Setter
或者Getter
- 不能是原生類型(String可以,它不是原生類型)
如果在初始前訪問lateinit
定義的屬性會拋出特定異常,指明該屬性沒有被初始化。
總結一波:我們需要區分Kotlin中和java中使用屬性的區別,對於Koltin
中使用【類名.屬性】等同於java中的【類名.屬性對應方法】,以及牢記Setter
的寫法,別寫錯了,導致循環調用,熟練使用幕後字段。重寫後的Getter
和Setter
會覆蓋之前的默認方法並不會衝突
總結
至此已經學完了Kotlin的【類的屬性和字段】的知識,多回顧多思考,繼續後續內容。