Kotlin 屬性與字段

聲明屬性

Kotlin 類中的屬性既可以用關(guān)鍵字 var 聲明為可變的,也可以用關(guān)鍵字 val 聲明為只讀的。

class Address {
    var name: String = "Holmes, Sherlock"
    var street: String = "Baker"
    var city: String = "London"
    var state: String? = null
    var zip: String = "123456"
}
  • 使用屬性,只要用名稱引用它即可浙宜。
fun copyAddress(address: Address): Address {
    val result = Address()  // Kotlin 中沒有“new”關(guān)鍵字
    result.name = address.name  // 將調(diào)用訪問(wèn)器
    result.street = address.street
    // ……
    return result
}

Getters 與 Setters

  • 聲明一個(gè)屬性的完整語(yǔ)法如下:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]
  • 其初始器(initializer)gettersetter都是可選的蛹磺。屬性類型如果可以從初始器 (或者從其 getter 返回值粟瞬,如下文所示)中推斷出來(lái),也可以省略萤捆。
var allByDefault: Int? // 錯(cuò)誤:需要顯式初始化器裙品,隱含默認(rèn) getter 和 setter
var initialized = 1 // 類型 Int、默認(rèn) getter 和 setter
  • 一個(gè)只讀屬性的語(yǔ)法和一個(gè)可變的屬性的語(yǔ)法有兩方面的不同:
    1俗或、只讀屬性的用 val 開始代替 var
    2市怎、只讀屬性不允許 setter
val simple: Int? // 類型 Int、默認(rèn) getter辛慰、必須在構(gòu)造函數(shù)中初始化
val inferredType = 1 // 類型 Int 区匠、默認(rèn) getter
  • 我們可以為屬性定義自定義的訪問(wèn)器,如果我們定義了一個(gè)自定義的 getter帅腌,那么每次訪問(wèn)該屬性時(shí)都會(huì)調(diào)用它驰弄;如果可以從 getter 中推斷出返回類型,則可以省略它速客。
val isEmpty: Boolean
    get() = this.size == 0

val isEmpty get() = this.size == 0  // 具有類型 Boolean
  • 如果我們定義了一個(gè)自定義的 setter戚篙,那么每次給屬性賦值時(shí)都會(huì)調(diào)用它(按照慣例,setter 參數(shù)的名稱是 value溺职,但是如果你喜歡你可以選擇一個(gè)不同的名稱)岔擂。
var stringRepresentation: String
    get() = this.toString()
    set(value) {
        setDataFromString(value) // 解析字符串并賦值給其他屬性
    }
  • 如果你需要改變一個(gè)訪問(wèn)器的可見性或者對(duì)其注解,但是不需要改變默認(rèn)的實(shí)現(xiàn)辅愿, 你可以定義訪問(wèn)器而不定義其實(shí)現(xiàn):
var setterVisibility: String = "abc"
    private set // 此 setter 是私有的并且有默認(rèn)實(shí)現(xiàn)

var setterWithAnnotation: Any? = null
    @Inject set // 用 Inject 注解此 setter

幕后字段

在 Kotlin 類中不能直接聲明字段智亮。當(dāng)一個(gè)屬性需要一個(gè)幕后字段時(shí),可以使用 field 標(biāo)識(shí)符在訪問(wèn)器中引用点待。需要注意的是阔蛉, field 標(biāo)識(shí)符只能用在屬性的訪問(wèn)器內(nèi)。

var counter = 0  // 注意:這個(gè)初始器直接為幕后字段賦值
    set(value) {
        if (value >= 0) field = value
    }

幕后屬性

如果你的需求不符合這套“隱式的幕后字段”方案癞埠,那么可以使用 幕后屬性(backing property)

private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap() // 類型參數(shù)已推斷出
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

編譯期常量

如果只讀屬性的值在編譯期是已知的状原,那么可以使用 const 修飾符將其標(biāo)記為編譯期常量。
這種屬性需要滿足以下:

  • 位于頂層或者是 object 聲明 或 companion object的一個(gè)成員
  • String 或原生類型值初始化
  • 沒有自定義 getter
const val CONST_VAL = 1
const val CONST_VAL_GET get() = 1  // error: 不能有自定義 getter
const val CONST_VAL_TEST :Any = 1  // error 需要是 String 或原生類型值初始化
fun testConstInFunction() {
    const val CONST_VAL = 1 // error: 需要位于頂層或者是 object 聲明 或 companion object 的一個(gè)成員
}
object Kotlin {
    const val CONST_VAL: String = "object 常量"
}
  • 這些屬性還可以用在注解中:
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"

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

延遲初始化屬性與變量

一般地苗踪,屬性聲明為非空類型必須在構(gòu)造函數(shù)中初始化颠区。 然而,這經(jīng)常不方便通铲。例如:屬性可以通過(guò)依賴注入來(lái)初始化毕莱, 或者在單元測(cè)試的 setup 方法中初始化。 這種情況下,你不能在構(gòu)造函數(shù)內(nèi)提供一個(gè)非空初始器朋截。 但你仍然想在類體中引用該屬性時(shí)避免空檢測(cè)蛹稍。

  • 針對(duì)上面情況,Kotlin 引入了 lateinit 修飾符部服,用于標(biāo)記該屬性唆姐。
public class MyTest {
    lateinit var subject: TestSubject

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

    @Test fun test() {
        subject.method()  // 直接解引用
    }
}

lateinit 修飾符只能用于在類體中的屬性(不是在主構(gòu)造函數(shù)中聲明的 var 屬性,并且僅當(dāng)該屬性沒有自定義 gettersetter 時(shí))廓八。
自 Kotlin 1.2 起奉芦,也用于頂層屬性與局部變量。該屬性或變量必須為非空類型剧蹂,并且不能是原生類型声功。
在初始化前訪問(wèn)一個(gè) lateinit 屬性會(huì)拋出一個(gè)特定異常,該異常明確標(biāo)識(shí)該屬性被訪問(wèn)及它沒有初始化的事實(shí)国夜。

  • 檢測(cè)一個(gè) lateinit var 是否已初始化(自 1.2 起)

Kotlin 可以通過(guò) .isInitialized 檢測(cè)一個(gè) lateinit var 是否已經(jīng)初始化過(guò):

if (foo::bar.isInitialized) {
    println(foo.bar)
}

注意:此檢測(cè)僅對(duì)可詞法級(jí)訪問(wèn)的屬性可用减噪,即聲明位于同一個(gè)類型內(nèi)、位于其中一個(gè)外圍類型中或者位于相同文件的頂層的屬性车吹。


覆蓋屬性


委托屬性

  • 最常見的一類屬性就是簡(jiǎn)單地從幕后字段中讀取(以及可能的寫入)醋闭。
  • 另一方面窄驹,使用自定義 getter 和 setter 可以實(shí)現(xiàn)屬性的任何行為。
  • 介于兩者之間证逻,屬性如何工作有一些常見的模式乐埠。一些例子:惰性值、 通過(guò)鍵值從映射讀取囚企、訪問(wèn)數(shù)據(jù)庫(kù)丈咐、訪問(wèn)時(shí)通知偵聽器等等。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末龙宏,一起剝皮案震驚了整個(gè)濱河市棵逊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌银酗,老刑警劉巖辆影,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異黍特,居然都是意外死亡蛙讥,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門灭衷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)次慢,“玉大人,你說(shuō)我怎么就攤上這事∑认瘢” “怎么了拭抬?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)侵蒙。 經(jīng)常有香客問(wèn)我造虎,道長(zhǎng),這世上最難降的妖魔是什么纷闺? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任算凿,我火速辦了婚禮,結(jié)果婚禮上犁功,老公的妹妹穿的比我還像新娘氓轰。我一直安慰自己,他們只是感情好浸卦,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布署鸡。 她就那樣靜靜地躺著,像睡著了一般限嫌。 火紅的嫁衣襯著肌膚如雪靴庆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天怒医,我揣著相機(jī)與錄音炉抒,去河邊找鬼。 笑死稚叹,一個(gè)胖子當(dāng)著我的面吹牛焰薄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扒袖,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼塞茅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了季率?” 一聲冷哼從身側(cè)響起野瘦,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚀同,沒想到半個(gè)月后缅刽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蠢络,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年衰猛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刹孔。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啡省,死狀恐怖娜睛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卦睹,我是刑警寧澤畦戒,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站结序,受9級(jí)特大地震影響障斋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜徐鹤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一垃环、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧返敬,春花似錦遂庄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至凛澎,卻和暖如春霹肝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背预厌。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工阿迈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人轧叽。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像刊棕,于是被迫代替她去往敵國(guó)和親炭晒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359