kotlin開發經驗談1

xingstarx發表於2017-12-13

筆者最近幾個月在學習kotlin,然後用來重構專案,反正是不斷踩坑中,踩的很開心?,這個過程中碰到了一些問題,值得記錄下來, 供大家參考。

如何定義一個非空變數

本次的問題是如何定義一個非空變數,有哪些實現手段呢?

在此之前,我先講講如何定義常量變數,為了方便學習kotlin的語法特性,推薦使用idea開發工具。

那麼現在創見一個java工程,選擇kotlin支援。 建立一個檔案,內容如下

class User {
    var name:String? = null
    val id:String? = null
}

fun main(args: Array<String>) {
    println("Hello World")

}
複製程式碼

在這裡我們定義了一個model類User,User類有兩個屬性,一個是變數name可空,一個是常量id可空

image.png

我們想知道這個檔案最終對應的java程式碼是什麼,有什麼辦法呢,我只會反編譯額。接著就編譯這個App.kt檔案,idea中選擇app.kt檔案,然後單擊右鍵Recompile App.kt,就會編譯出class檔案,接著我們用JD_GUI反編譯工具,去檢視這兩個class檔案的內容

image.png

image.png

這個就是最終的反編譯出來的java程式碼,我們可以理解為kotlin編譯後得到的就是這樣的java程式碼。 我們關注的重點是User類,id是定義的一個常量,反編譯出來的程式碼裡面將它設定了為final型別,預設的訪問級別也是private,這也是kotlin的設計理念(不知道說的對不對^_^),屬性私有化,對外提供geter,seter。而變數name,就跟我們平常定義java屬性的方式類似,private String name,到此,如何定義一個常量變數就講完了,對應生成的java程式碼我們也看到了,接下來回到正題,如何定義一個非空變數,有哪些手段?

先看一段程式碼片段吧(來自https://github.com/leanote/leanote-android)

image.png

image.png

我們拿這個NoteFragment來描述,我需要在onCreate方法中初始化這個mNoteFragment,但是我不想讓kotlin的程式碼中,出現mNoteFragment?.setMode(mode)這樣的程式碼?

image.png

不想各個地方都出現這樣的程式碼,如果把mNoteFragment定義為非空的那就好了,說幹就幹,該如何修改呢?

不可能直接這樣改 var mNoteFragment: NoteFragment = NoteFragment.newInstance(),這樣有問題的,就不多說了。

考慮到kotlin的語言特性我想到的只有 lateinit var mNoteFragment: NoteFragment 這樣在onCreate方法裡面初始化是可以的。 var mNoteFragment: NoteFragment by Delegates.notNull<NoteFragment>()和這種委託的模式

我們先看這一段程式碼,lateinit方式的

class MainActivity {
    lateinit var mNoteFragment: String
    fun onCreate() {
       mNoteFragment = newInstance()
    }
    companion object {
        fun newInstance():String {
            return "NoteFragment"
        }
    }
}
複製程式碼

這種情況下生成的java程式碼如下

image.png

lateinit var mNoteFragment: String 被翻譯成了@NotNull public String mNoteFragment mNoteFragment被定義為了public訪問級別

接著看看委託模式下的

import kotlin.properties.Delegates

class MainActivity {
    var mNoteFragment: String by Delegates.notNull<String>()
    fun onCreate() {
       mNoteFragment = newInstance()
    }
    companion object {
        fun newInstance():String {
            return "NoteFragment"
        }
    }
}
複製程式碼

反編譯的java程式碼比較複雜,暫時也沒有深究,感覺要麻煩多了

image.png

我們定義的mNoteFragment屬性不見了,反而多了一個mNoteFragment$delegate屬性,而且還是在構造方法中做的初始化操作,以及一個$$deletegatedProperties在靜態程式碼塊初始化的不知道什麼東西的東西,雖然沒有了mNoteFragment,但是還是有對應的geter,setter方法,具體就不深究了,暫時功力有限。

總結

到此為止,講完了。 定義一個非空屬性,基本上常用的手段就是lateinit和委託模式。

相關文章