1. 程式人生 > >Kotlin基礎語法-屬性(Property)與域(Field)

Kotlin基礎語法-屬性(Property)與域(Field)

屬性(Property)與域(Field)

宣告屬性

Kotlin 中的類可以擁有屬性. 可以使用 var 關鍵字宣告為可變(mutable)屬性, 也可以使用 val 關鍵字宣告為只讀屬性.

public class Address { 
  public var name: String = ...
  public var street: String = ...
  public var city: String = ...
  public var state: String? = ...
  public var zip: String = ...
}

使用屬性時, 只需要簡單地通過屬性名來參照它, 和使用 Java 中的域變數(field)一樣:

fun copyAddress(address: Address): Address {
  val result = Address() // Kotlin 中沒有 'new' 關鍵字
  result.name = address.name // 將會呼叫屬性的訪問器方法
  result.street = address.street
  // ...
  return result
}

取值方法(Getter)與設值方法(Setter)

宣告屬性的完整語法是:

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

其中的初始化器(initializer), 取值方法(getter), 以及設值方法(setter)都是可選的. 如果屬性型別可以通過初始化器自動推斷得到, 或者可以通過這個屬性覆蓋的基類成員屬性推斷得到, 則屬性型別的宣告也可以省略.

示例:

var allByDefault: Int? // 錯誤: 需要明確指定初始化器, 此處會隱含地使用預設的取值方法和設值方法
var initialized = 1 // 屬性型別為 Int, 使用預設的取值方法和設值方法

只讀屬性宣告的完整語法與可變屬性有兩點不同: 由 val

 開頭, 而不是 var, 並且不允許指定設值方法:

val simple: Int? // 屬性型別為 Int, 使用預設的取值方法, 屬性值必須在構造器中初始化
val inferredType = 1 // 屬性型別為 Int, 使用預設的取值方法

我們可以編寫自定義的訪問方法, 與普通的函式很類似, 訪問方法的位置就在屬性定義體之內. 下面是一個自定義取值方法的示例:

val isEmpty: Boolean
  get() = this.size == 0

自定義設值方法的示例如下:

var stringRepresentation: String
  get() = this.toString()
  set(value) {
    setDataFromString(value) // 解析字串內容, 並將解析得到的值賦給對應的其他屬性
  }

Kotlin 的程式設計慣例是, 設值方法的引數名稱為 value, 但如果你喜歡, 也可以選擇使用不同的名稱.

如果你需要改變屬性訪問方法的可見度, 或者需要對其添加註解, 但又不需要修改它的預設實現, 你可以定義這個方法, 但不定義它的實現體:

var setterVisibility: String = "abc"
  private set // 設值方法的可見度為 private, 並使用預設實現

var setterWithAnnotation: Any? = null
  @Inject set // 對設值方法新增 Inject 註解

屬性的後端域變數(Backing Field)

Kotlin 的類不能擁有域變數. 但是, 使用屬性的自定義訪問器時, 有時會需要後端域變數(backing field). 為了這種目的, Kotlin 提供了一種自動的後端域變數, 可以通過 field 識別符號來訪問:

var counter = 0 // 初始化給定的值將直接寫入後端域變數中
  set(value) {
    if (value >= 0)
      field = value
  }

field 識別符號只允許在屬性的訪問器函式內使用.

如果屬性 get/set 方法中的任何一個使用了預設實現, 或者在 get/set 方法的自定義實現中通過 field 識別符號訪問屬性, 那麼編譯器就會為屬性自動生成後端域變數.

比如, 下面的情況不會存在後端域變數:

val isEmpty: Boolean
  get() = this.size == 0

後端屬性(Backing Property)

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

private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
  get() {
    if (_table == null)
      _table = HashMap() // 型別引數可以自動推斷得到, 不必指定
    return _table ?: throw AssertionError("Set to null by another thread")
  }

不管從哪方面看, 這種方案都與 Java 中完全相同, 因為後端私有屬性的取值方法與設值方法都使用預設實現, 我們對這個屬性的訪問將被編譯器優化, 變為直接讀寫後端域變數, 因此不會發生不必要的函式呼叫, 導致效能損失.

編譯期常數值

如果屬性值在編譯期間就能確定, 則可以使用 const 修飾符, 將屬性標記為_編譯期常數值(compile time constants)_. 這類屬性必須滿足以下所有條件:

  • 必須是頂級屬性, 或者是一個 object 的成員
  • 值被初始化為 String 型別, 或基本型別(primitive type)
  • 不存在自定義的取值方法

這類屬性可以用在註解內:

const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"

@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... }

延遲初始化屬性(Late-Initialized Property)

通常, 如果屬性宣告為非 null 資料型別, 那麼屬性值必須在構造器內初始化. 但是, 這種限制很多時候會帶來一些不便. 比如, 屬性值可以通過依賴注入來進行初始化, 或者在單元測試程式碼的 setup 方法中初始化. 這種情況下, 你就無法在構造器中為屬性編寫一段非 null 值的初始化程式碼, 但你仍然希望在類內參照這個屬性時能夠避免 null 值檢查.

要解決這個問題, 你可以為屬性新增一個 lateinit 修飾符:

public class MyTest {
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }

    @Test fun test() {
        subject.method()  // 直接訪問屬性
    }
}

這個修飾符只能用於 var 屬性, 而且只能是宣告在類主體部分之內的屬性(不可以是主構造器中宣告的屬性), 而且屬性不能有自定義的取值方法和設值方法. 屬性型別必須是非 null 的, 而且不能是基本型別.

在一個 lateinit 屬性被初始化之前訪問它, 會丟擲一個特別的異常, 這個異常將會指明被訪問的屬性, 以及它沒有被初始化這一錯誤.

屬性的覆蓋

參見 成員的覆蓋

委託屬性(Delegated Property)

最常見的屬性只是簡單地讀取(也有可能會寫入)一個後端域變數. 但是, 通過使用自定義的取值方法和設值方法, 我們可以實現屬性任意複雜的行為. 在這兩種極端情況之間, 還存在一些非常常見的屬性工作模式. 比如: 屬性值的延遲載入, 通過指定的鍵值(key)從 map 中讀取資料, 訪問資料庫, 屬性被訪問時通知監聽器, 等等.

相關推薦

Kotlin基礎語法-屬性(Property)(Field)

屬性(Property)與域(Field) 宣告屬性 Kotlin 中的類可以擁有屬性. 可以使用 var 關鍵字宣告為可變(mutable)屬性, 也可以使用 val 關鍵字宣告為只讀屬性. public class Address { public var

kotlin基礎語法

映射 lambda white start 轉換 檢查 posit was tom 1. 包定義 package package my.demo2. 方法定義 fun fun sum(a: Int, b: Int): Int {//定義方法的關鍵字fun;方法名sum;變

Python:基礎語法:緒論註釋

span log color spa str 寫法 單行 單行註釋 strong 緒論 註釋 1 # 這是一條單行註釋 2 3 ‘‘‘ 4 這是多行註釋的寫法 5 通常放在前面充當說明性的文字 6 或者 7 用在註釋需要換行的地方 8 ‘‘‘ Python:基礎

Kotlin基礎語法之 "=="和"==="的區別

        總體來說kotlin中==比較的是數值是否相等, 而===比較的是兩個物件的地址是否相等, 見如下程式碼: val a: Int = 999 val b: Int? = a val c: Int?

(一)Kotlin 基礎語法

文章目錄 一、 Kotlin語法 1. 變數與常量 * 常量: * 變數: * 字串模板: 2. 函式(得函式者得天下) 3.

Kotlin基礎語法學習筆記

Kotlin簡介 Kotlin是一門與Swift類似的靜態型別JVM語言,由JetBrains設計開發並開源。與Java相比,Kotlin的語法更簡潔、更具表達性,而且提供了更多的特性,比如,高階函式

css基礎語法一(選擇器css導入方式)

數字 mic link html clas ref height font 兼容 頁面中,所有的CSS代碼,需要寫入到<style></style>標簽中。style標簽的type屬性應該選擇text/css,但是type屬性可以省略。 CS

python簡介基礎語法

twisted 版本 lse 組合 ack list 針對 如果 rap 1. python簡介: python是一種解釋型、面向對象、動態數據類型的高級程序設計語言。 python由Guido van Rossum與1989年底發明,第一個公開發行版發行與1991

awk基礎語法簡單示例

文本處理工具awk介紹 ??awk:Aho, Weinberger, Kernighan,報告生成器,格式化文本輸出 ?? 有多種版本:?? ??New awk(nawk),GNU awk( gawk) ????gawk:模式掃描和處理語言 ?? 基本用法: ???? awk [options]

go基礎語法-常量枚舉

大寫 import 需要 枚舉類型 file fun ava package code 常量與枚舉 1.常量定義 用const關鍵字修飾常量名並賦值,常量命名不同於java等語言,golang中一般用小寫,因為在golang中首字母大寫表示public權限 const a

Java基礎語法 - 函式方法

java 是一門面向物件程式設計,其它語言中的函式也就是java中的方法   方法的基本使用方法 1 package com.demo7; 2 3 /* 4 * 函式/方法 5 * 6 * 定義格式: 7 * 修飾符 返回值型別 方法名(引數型別 引數1, 引

Python的基礎語法 13 深拷貝淺拷貝

python中的深copy和淺copy bytes Python bytes/str bytes 在Python3中作為一種單獨的資料型別,不能拼接,不能拼接,不能拼接 >>> '

Kotlin學習筆記1_基礎語法

1. What’s Kotlin? – 引自百度百科 Kotlin 是一個用於現代多平臺應用的靜態程式語言,由 JetBrains 開發。 Kotlin可以編譯成Java位元組碼,也可以編譯成Java

Java中的基礎語法定義

Java中的基礎語法 首先Java是一個完全的面嚮物件語言。這一點決定了Java程式是由一系列的物件組成的,這些物件通過呼叫彼此的方法來完成程式的執行。 接下來理解一下Java中的幾個概念: 類:類是一個模板,在類中定義了一種物件的行為(方法、函式)和狀態(

快速學習Kotlin(一)基礎語法

變數和不可變數 在kotlin中我們在宣告一個變數的時候,採用var作為修飾符來修飾一個變數,而採用val修飾符來修飾一個不可變數。這裡需要注意一點,這是val是被定義為一個叫做不可變數,而不是一個常量,這兩者是有區別的。可以把被val修飾的變數比作在Java中的final

快速學習Python基礎語法Java的不同之處

1、Python識別符號中與Java的不同 Python識別符號中以下劃線開頭的識別符號具有特殊意義。 以單下劃線開頭 _foo 的代表不能直接訪問的類屬性,需通過類提供的介面進行訪問,不能用 from xxx import * 而匯入; 以雙下劃線開頭的 __foo

Python 基礎語法應用

Python 基礎語法 1.標準化輸入輸出 input() msg = input() msg = input("提示資訊") # input() 的接收結果都是str型別,必要的時候需要做些型別轉換 print("字串" + "拼接") print("字串"

python基礎語法總結(六)-- python類OOP面向物件特性

python常用系統函式方法與模組 python基礎語法總結(一)-- python型別轉換函式+檔案讀寫 python基礎語法總結(二)-- 函式function python基礎語法總結(三)-- 數與字串 python基礎語法總結(四)-- list列表

python基礎語法總結(三)-- 數字串

python常用系統函式方法與模組 python基礎語法總結(一)-- python型別轉換函式+檔案讀寫 python基礎語法總結(二)-- 函式function python基礎語法總結(三)-- 數與字串 python基礎語法總結(四)-- list列表

Kotlin系列之基礎語法

標籤: Kotlin      Kotlin基礎語法 目錄: 簡述: Kotlin的基本語法的介紹,先從整體上體會kotlin的程式設計風格。 一、包的宣告 在Kotlin中定義包與Java有點不同,在Kotlin中目錄與包結構無需匹配,