【Kotlin從入門到深坑】之類的屬性和字段

簡介

本篇博客主要是介紹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é)一波:通過上面的介紹我們了解了什么是屬性以及什么是字段,在javaKotlin中其含義是一致的。


屬性和字段

聲明屬性

對于Kotlin的類可以有屬性。我們之前也說過可以通過var聲明可變屬性,val聲明只讀屬性,或許你會(huì)問了,為什么不是叫字段而是叫屬性呢?因?yàn)?code>Kotlin類中聲明的變量,都會(huì)提供默認(rèn)的getset(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】可以推斷出類型,則【類型】也可以省略。

屬性通過varval去聲明得到只讀屬性和可變屬性,那他們的區(qū)別究竟是什么呢?

只讀屬性和可變屬性的區(qū)別:

  • 只讀屬性使用val聲明,可變屬性使用var聲明

  • 只讀屬性不允許setter

看到此處你或許會(huì)感嘆Kotlin的厲害之處,省了不知多少時(shí)間,但有些人或許會(huì)感嘆了,如果我想自己定義屬性的訪問方法又怎么弄呢?像java再自定義方法嗎?會(huì)不會(huì)和默認(rèn)的setter或者getter沖突呢?對于疑問我們一一解答。


自定義Getters和Setters

編寫GettersSetters非常像一般的不同方法,在屬性聲明內(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 又是什么鬼。。。

好,我們說明一下:

  • valuesetter的參數(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后其GetterSetter,都是私有的,外部都不可以訪問也就是說 person._table 是不允許的。也就進(jìn)行了隱藏。又因?yàn)槟J(rèn)的SetterGetter調(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)用,熟練使用幕后字段。重寫后的GetterSetter 會(huì)覆蓋之前的默認(rèn)方法并不會(huì)沖突


總結(jié)

至此已經(jīng)學(xué)完了Kotlin的【類的屬性和字段】的知識(shí),多回顧多思考,繼續(xù)后續(xù)內(nèi)容。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容