筆者最近幾個月在學習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可空
我們想知道這個檔案最終對應的java程式碼是什麼,有什麼辦法呢,我只會反編譯額。接著就編譯這個App.kt檔案,idea中選擇app.kt檔案,然後單擊右鍵Recompile App.kt,就會編譯出class檔案,接著我們用JD_GUI反編譯工具,去檢視這兩個class檔案的內容
這個就是最終的反編譯出來的java程式碼,我們可以理解為kotlin編譯後得到的就是這樣的java程式碼。
我們關注的重點是User類,id是定義的一個常量,反編譯出來的程式碼裡面將它設定了為final型別,預設的訪問級別也是private,這也是kotlin的設計理念(不知道說的對不對^_^),屬性私有化,對外提供geter,seter。而變數name,就跟我們平常定義java屬性的方式類似,private String name
,到此,如何定義一個常量變數就講完了,對應生成的java程式碼我們也看到了,接下來回到正題,如何定義一個非空變數,有哪些手段?
先看一段程式碼片段吧(來自https://github.com/leanote/leanote-android)
我們拿這個NoteFragment來描述,我需要在onCreate方法中初始化這個mNoteFragment,但是我不想讓kotlin的程式碼中,出現mNoteFragment?.setMode(mode)
這樣的程式碼?
不想各個地方都出現這樣的程式碼,如果把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程式碼如下
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程式碼比較複雜,暫時也沒有深究,感覺要麻煩多了
我們定義的mNoteFragment屬性不見了,反而多了一個mNoteFragment$delegate屬性,而且還是在構造方法中做的初始化操作,以及一個$$deletegatedProperties在靜態程式碼塊初始化的不知道什麼東西的東西,雖然沒有了mNoteFragment,但是還是有對應的geter,setter方法,具體就不深究了,暫時功力有限。
總結
到此為止,講完了。 定義一個非空屬性,基本上常用的手段就是lateinit和委託模式。