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