Kotlin-Anko學習(5)Kotlin語法-屬性缕陕、字段掷漱、接口

本系列文章來學習 Kotlin 和 Anko 插件 通過 Kotlin 開發(fā)一個 Android 項目。

Kotlin-Anko學習(1) Kotlin榄檬、Anko 介紹
Kotlin-Anko學習(2) Kotlin 語法基礎-基本類型
Kotlin-Anko學習(3) Kotlin 語法基礎-關鍵字 package卜范、Import、if鹿榜、when海雪、for、while舱殿、return奥裸、break、continue
Kotlin-Anko學習(4) Kotlin語法-類沪袭、繼承湾宙、抽象類
Kotlin-Anko學習(5) Kotlin語法-屬性、字段冈绊、接口

屬性

Kotlin 中 屬性的聲明包括:關鍵字 val或var 侠鳄、屬性名、屬性類型死宣、初始器伟恶、訪問器組成 如下:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]
//示例
    var allByDefault:Int ?= null
    get() = if(field ==null){
       0
    }else{
      field
    }
// set訪問器只有在var 可變屬性中存在 val 沒有set訪問器
    set(value){
       field = if(value==null){
            0
       }else{
          value-2 
       } 
    }

以上示例是完整的屬性聲明,一般初始器(initializer)毅该、訪問器getter 和 setter 都是可選的博秫。屬性類型如果可以從初始器 、訪問器中推斷出來眶掌,也可以省略挡育。總之遵循根據(jù)上下文推算出來的就可以不去特意聲明朴爬。這也是kotlin 簡潔性的特征之一即寒。

  • Kotlin中,給屬性直接賦值,或者調用屬性的值蒿叠,其實質是調用了訪問器 get、set 方法蚣常,這點跟java是不同的市咽。
  • 如果你需要改變一個訪問器的可見性或者對其注解,但是不需要改變默認的實現(xiàn)抵蚊, 你可以定義訪問器而不定義其實現(xiàn)施绎。

也就是在類外禁止改變 屬性var 的值,可以將其聲明為val 或者 自定義var set訪問器的可見性 private 如下

class Kot{
var allByDefault:Int ?= null
        get() = if(field ==null){
            0
        }else{
            field
        }
      //用private進行修飾
       private set(value){
            field = if(value==null){
                0
            }else{
                value-2
            }
        }
}
//Kot.allByDefault= 1//error: 不允許設置

幕后字段

  • Kotlin 中不能直接聲明字段贞绳,當屬性需要字段時谷醉,會提供一個幕后字段。用field標識
  • Kotlin 中存在幕后字段的情況:
    1. 屬性訪問器默認實現(xiàn)會隱式使用幕后字段冈闭。
    2. 自定義訪問器通過field顯式引用幕后字段俱尼。
    var age : Int = 15
    //上面這句代碼其實和下面的代碼是等價的,沒有區(qū)別萎攒。
    var age: Int = 15
        set(value) {
            field = value
        }
        get() {
            return field
        }

上面是kotlin對于幕后字段的使用遇八,如何理解屬性和字段呢? 比如在java中耍休,一個person類中刃永,在外部看來有一個getAge()和setAge(int age)方法,說明person有一個age 屬性羊精, 但是不能說person中一定有age這個字段斯够。而在kotlin 中 可以通過關鍵字var/val 聲明屬性,但是沒有關鍵字來聲明字段:如下:

    //java
    class Person {
        private int age =15; //age 是一個字段
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    new Person.getAge()//獲取person的age屬性
  //kotlin
   class Person {
        var age: Int = 15//person 的一個age屬性
        set(value) {
            field = value  // field 為一個幕后字段的標識
        }
        get() {
            return field
        }
    }

以上兩段代碼生成的.class文件是相同的喧锦。這就是我對 backing field 的理解读规。

幕后屬性

kotlin 中可以通過聲明一個私有的屬性作為一個幕后屬性

class Base{
    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")
    }
}

fun main(args: Array<String>) {
    var base = Base()
    println("table = ${base.table}" )
   
}

幕后屬性的使用與java的字段相似,解決隱式幕后字段不能處理的問題燃少,通過私有屬性的get/set來優(yōu)化掖桦。也是Kotlin對于空指針的一種解決方案。

編譯期常量

通過 const 修飾的屬性 滿足如下條件:

  • 位于頂層或者是 object 的一個成員
  • 用 String 或原生類型 值初始化
  • 沒有自定義 getter
//編譯期常量
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"

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

延遲初始化屬性與變量

通過 lateinit 修飾的屬性 滿足如下條件:

  • 只能用于在類體中的屬性(不是在主構造函數(shù)中聲明的 var 屬性供汛,并且僅當該屬性沒有自定義 getter 或 setter 時)
  • 用于頂層屬性與局部變量枪汪。該屬性或變量必須為非空類型,并且不能是原生類型
  • 在初始化前訪問一個 lateinit 屬性會拋出一個特定異常怔昨,明確標識該屬性被訪問及它沒有初始化

//延遲性屬性的使用如下:

public class MyTest {
    class TestSubject{
        fun method(){
            println("TestSubject.method()")
        }
    }
    lateinit var subject: TestSubject
    fun setup() {
        subject = TestSubject()
    }
   fun test() {
        subject.method()  // 直接解引用
    }
}

fun main(args: Array<String>) {
    var test = MyTest()
    test.setup()//如果不調用setup()初始化雀久,會報如下錯誤
    test.test()
   
}

初始化前使用延遲性屬性,會報如下錯誤:

Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property subject has not been initialized
    at MyTest.test(Simplest version.kt:12)
    at Simplest_versionKt.main(Simplest version.kt:18)

檢測一個 lateinit var 是否已初始化 可以通過引用屬性的.isInitialized來做判斷:

class Foo {
    lateinit var bar: String
    fun setup() {
        println("sssss ${this::bar.isInitialized}"  )
        bar="value"
        println("xxxxx ${this::bar.isInitialized}")
    }

}

fun main(args: Array<String>) {
    Foo().setup()
}

輸出結果:

sssss false
xxxxx true

屬性和字段的基本使用就寫完了趁舀,由于篇幅問題赖捌,再加上一個接口的學習。

接口

接口的定義與實現(xiàn)

Kotlin 中使用關鍵字 interface 來定義接口,包含抽象方法的聲明越庇、也可以有方法的實現(xiàn)罩锐。這就跟java有區(qū)別了,如果聲明的方法沒有方法體卤唉,默認是抽象方法涩惑,子類必須實現(xiàn),有方法體的子類可以選擇性實現(xiàn)桑驱。

interface MyInterface {
    //默認抽象方法
    fun bar()
    fun foo() {
      // 可選的方法體
    }
} 
class Child : MyInterface {
    override fun bar() {
        // 方法體
    }
    
}

接口中定義的屬性

Kotlin 中接口可以定義抽象屬性 或者提供訪問器的實現(xiàn)竭恬,但是訪問器的實現(xiàn)不能包含幕后字段(上面有對幕后字段的理解)。

interface MyInterface {
    val prop: Int // 抽象的

    val propertyWithImplementation: String
        get() = "foo"

    fun foo() {
        println(prop)
        println(propertyWithImplementation)
    }
}

class Child : MyInterface {
    override val prop: Int = 29
    override val propertyWithImplementation: String
        get() = super.propertyWithImplementation
}

fun main(args: Array<String>) {
    println(Child().propertyWithImplementation)
    Child().foo()
}

輸出結果:

foo
29
foo

解決覆蓋沖突

現(xiàn)多個接口時熬的,可能會遇到同一方法繼承多個實現(xiàn)的問題痊硕,在類的繼承中已經(jīng)講解過,請參考上一篇押框。

參考

http://www.reibang.com/writer#/notebooks/19396434/notes/22305825/preview
https://liyuanbiao.wordpress.com/2017/07/30/ru-he-li-jiekotlin-zhong-shu-xing/

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末岔绸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子橡伞,更是在濱河造成了極大的恐慌亭螟,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骑歹,死亡現(xiàn)場離奇詭異预烙,居然都是意外死亡,警方通過查閱死者的電腦和手機道媚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門扁掸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人最域,你說我怎么就攤上這事谴分。” “怎么了镀脂?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵牺蹄,是天一觀的道長。 經(jīng)常有香客問我薄翅,道長沙兰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任翘魄,我火速辦了婚禮鼎天,結果婚禮上,老公的妹妹穿的比我還像新娘暑竟。我一直安慰自己斋射,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著罗岖,像睡著了一般涧至。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桑包,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天南蓬,我揣著相機與錄音,去河邊找鬼捡多。 笑死蓖康,一個胖子當著我的面吹牛铐炫,可吹牛的內(nèi)容都是我干的垒手。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼倒信,長吁一口氣:“原來是場噩夢啊……” “哼科贬!你這毒婦竟也來了?” 一聲冷哼從身側響起鳖悠,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤榜掌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后乘综,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體憎账,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年卡辰,在試婚紗的時候發(fā)現(xiàn)自己被綠了胞皱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡九妈,死狀恐怖反砌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情萌朱,我是刑警寧澤宴树,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站晶疼,受9級特大地震影響酒贬,放射性物質發(fā)生泄漏。R本人自食惡果不足惜翠霍,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一同衣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧壶运,春花似錦耐齐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耸携。三九已至,卻和暖如春辕翰,著一層夾襖步出監(jiān)牢的瞬間夺衍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工喜命, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沟沙,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓壁榕,卻偏偏與公主長得像矛紫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子牌里,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354