1. 程式人生 > >Kotlin 全面學習之路 (八) -- 屬性與欄位

Kotlin 全面學習之路 (八) -- 屬性與欄位

1、 宣告屬性

在 Kotlin 中 屬性分為 可變屬性只讀屬性

  • var 可變
  • val 只讀

示例;

class Mike {
    val name: String = "Mike"
    var age: Int = 25
}

2、完整的屬性宣告

宣告一個屬性的完整語法為:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]

其中 初始器(initializer)getter

setter 都是可選的。

我們可以自定義訪問器,具體場景為新建一個可以判斷是否為正方形的矩形類:

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {    // 屬性的獲取函式宣告
            return height == width
        }
}

一個自定義 setter 的例子;

var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value
) // 解析字串並賦值給其他屬性 }

如果要 改變一個訪問器的可見性或者對其註解,那麼不需要改變其預設實現,只需要定義該屬性的訪問器而不是其實現,以下為例:

var setterVisibility: String = "abc"
private set // 此 setter 是私有的並且有預設實現
var setterWithAnnotation: Any? = null
@Inject set // 用 Inject 註解此 setter

3、Backing Field

自己對 Kotlin 中相關 Backing Field 的內容比較疑惑,單獨寫一篇部落格來記錄,具體詳見。

4、後端屬性(Backing Property)

如果你希望實現的功能無法通過這種 “隱含的後端域變數” 方案來解決, 你可以使用 後端屬性(backing property) 作為替代方案:

private var _table: Map

5、編譯期常量

在闡述 編譯期常量前,我們需要先理解 執行時常量編譯期常量

  • 執行時常量是編譯時並不知道其值,真正執行的時候才獲取
  • 編譯期常量是編譯時候就知道其值的常量
  • kotlin中 val 並不是編譯期常量,可通過反射的方式修改值,要將其轉成編譯期常量需要加上 const 關鍵詞,可提高執行效率。

已知值的屬性可以使用 const 修飾符標記為 編譯期常量,不過這些屬性需要滿足以下要求:

  • 位於頂層或者是 object 的一個成員。驗證這一條件十分容易,在一個類的屬性前新增 const 修飾符,此時你會看到錯誤資訊:const 'val' are only allowed on top level or in object
  • 用 String 或原生型別初始化 。同樣可以在程式碼中進行驗證 。
  • 沒有自定義 getter 。同樣可以在程式碼中進行驗證 。

這些屬性可以用在註解中:

const val SUBSYSTEM_DEPRECATED: String = "This subsystem is depr
ecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }

6、延遲初始化屬性與變數

一般的,屬性宣告為 非空型別 必須在建構函式中 初始化,但是有些情況下,我們不能在建構函式內提供一個非空初始化屬性,比如需要一個類物件,但是此類物件需要通過一系列操作才可以得到,同時你還想在類體中引用該物件是避免空檢查,那麼此時延遲初始化屬性就是必要的了。

為了實現延遲初始化屬性,我們可以使用 lateinit 修飾符來標記該物件(屬性)。

public class People{
  lateinit var dog: Dog()

  fun setDog(dog: Dog){
    this.dog = dog
  }

  fun showDogInfo(){

    //dog?.show()
    //dog!!.show()
    // 此時就不用做空檢查,以上兩行程式碼就沒有必要了
    dog.show()
  }  
}

在初始化前訪問一個 lateinit 屬性會丟擲一個特定異常,該異常明確標識該屬 性被訪問及它沒有初始化的事實。

7、覆蓋屬性

子類覆蓋父類的相應屬性使用 override 修飾符修飾該屬性。

  • var 屬性可以覆蓋 val 屬性,反之不行
  • 每個宣告的屬性可以由具有初始化器的屬性或者具有 getter 方法的屬性覆蓋。

8、委託屬性

自己對 Kotlin 中相關委託的內容比較疑惑,單獨寫一篇部落格來記錄,具體詳見。

參考資料