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

簡介

本篇博客主要是介紹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的方法,則是可讀屬性,反之亦然。

總結一波:通過上面的介紹我們瞭解了什麼是屬性以及什麼是字段,在javaKotlin中其含義是一致的。


屬性和字段

聲明屬性

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

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

只讀屬性和可變屬性的區別:

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

  • 只讀屬性不允許setter

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


自定義Getters和Setters

編寫GettersSetters非常像一般的不同方法,在屬性聲明內部,舉例:

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 又是什麼鬼。。。

好,我們說明一下:

  • valuesetter的參數,其類型同於屬性的類型,不爽你也可以換個其他名字。。

  • 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後其GetterSetter,都是私有的,外部都不可以訪問也就是說 person._table 是不允許的。也就進行了隱藏。又因爲默認的SetterGetter調用私有屬性會被進行優化,所以不會引入函數調用開銷。


編譯期常量

kotlin中已知值得屬性可以使用const 標記爲編譯期常量。

它需要滿足以下條件:

  • 使用val聲明的常量
  • 位於頂層或者object的一個成員
  • String或者原生類型值初始化
  • 沒有自定義Getter

延遲初始化屬性

對於非空屬性,在聲明時必須對其進行初始化,如果想進行延遲初始化,可以使用lateinit標記,代碼舉例:

lateinit var name: String

需要注意以下幾點

  • 該修飾符只能用於類體中不是方法中的屬性
  • 沒有自定義Setter或者Getter
  • 不能是原生類型(String可以,它不是原生類型)

如果在初始前訪問lateinit定義的屬性會拋出特定異常,指明該屬性沒有被初始化。

總結一波:我們需要區分Kotlin中和java中使用屬性的區別,對於Koltin中使用【類名.屬性】等同於java中的【類名.屬性對應方法】,以及牢記Setter的寫法,別寫錯了,導致循環調用,熟練使用幕後字段。重寫後的GetterSetter 會覆蓋之前的默認方法並不會衝突


總結

至此已經學完了Kotlin的【類的屬性和字段】的知識,多回顧多思考,繼續後續內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章