時間:Jul, 4, 2017
原文鏈接:https://antonioleiva.com/kotlin-from-java/
Kotlin最神奇特性之一是它能與Java完全集成。這就是說盡管你的應用程序的所有代碼都是用Java編寫的,而你仍然可以在Kotlin中創建一個類,從Java中使用它,且不會出現任何問題。
這有兩個好處:
-
你可以在Java項目中使用Kotlin:在任何已經啟動的項目中,你可以現在開始用Kotlin編寫新的代碼。然后從Java代碼中調用它。
- 如果你對Kotlin還心有余悸,可以在Java中做這個部分:很多人問我在Android上的某些情況下,Kotlin是否有不足。理論上,所有事情都能夠勝任,但實際上,還無法知道(目前,還沒有人用Kotlin在Android上完成“所有事情”)。事實是,這無關緊要,如果有些操作不能在Kotlin中完成,還可以回Java中去實現它。
今天我們將看看這種兼容性是如何工作的,以及怎樣從Java使用Kotlin代碼。
軟件包級別的函數
在Kotlin中,函數不需要在類中,但Java不是的。那么我們如何調用函數呢?試想一下,我們有一個文件utils.kt,如下所示:
1 fun logD(message: String) { 2 Log.d("", message) 3 } 4 5 fun logE(message: String) { 6 Log.e("", message) 7 }
在Java中,我們可以通過UtilsKt類來訪問它們,並使用一些靜態方法:
1 UtilsKt.logD("Debug"); 2 UtilsKt.logE("Error");
在之前的文章,你已經看到我喜歡擴展函數。而在Java中,它們如何做?如我們有以下:
1 fun ViewGroup.inflate(resId: Int, attachToRoot: Boolean = false): View { 2 return LayoutInflater.from(context).inflate(resId, this, attachToRoot) 3 }
注意:
雖然它們可能在某個時候出現,但我還沒有明確地對此進行講解。函數的自變量可能有默認值。這就是說,如果我們不特別指明,它們就使用在聲明時指定的值。如我們要在Java中使用,這就阻止我們使用方法重載。
該函數用於ViewGroup
。它收到一個布局,並在其父視圖使其膨脹。
如果我們要在Java中使用它,會得到什么?
1 View v = UtilsKt.inflate(parent, R.layout.view_item, false);
如你所見,應用此函數的對象(接收方)是作為參數添加到函數中。另外,由於在Java中我們不能使用默認值,可選擇參數是強制性的。
如果要在Java中生成相應的重載,你可以為該函數使用@JvmOverloads注釋。這樣,你不需要在Java中指定false:
1 @JvmOverloads 2 fun ViewGroup.inflate(resId: Int, attachToRoot: Boolean = false): View { 3 return LayoutInflater.from(context).inflate(resId, this, attachToRoot) 4 }
1 View v = UtilsKt.inflate(parent, R.layout.view_item);
如果你希望在Java中使用時指定類名稱,則可以使用注釋來修改它。在文件utils.kt中,添加在package之前:
1 @file:JvmName("AndroidUtils")
現在Java中的類將被命名:
1 AndroidUtils.logD("Debug"); 2 AndroidUtils.logE("Error"); 3 View v = AndroidUtils.inflate(parent, R.layout.view_item, false);
實例和靜態字段
在Java中,我們使用字段來存儲狀態。它們可以是實例字段,這意味着每個對象都有自己的,或靜態的(所有類的實例都將共享它們)。
如果我們嘗試在Kotlin中找到對應的,那么它將是屬性和伴隨對象。如果我們有這樣一個類:
1 class App : Application() { 2 3 val appHelper = AppHelper() 4 5 companion object { 6 lateinit var instance: App 7 } 8 9 override fun onCreate() { 10 super.onCreate() 11 instance = this 12 } 13 14 }
這在Java中是如何工作?您可以簡單地訪問作為靜態字段的伴隨對象,以及使用getter和setter的屬性:
1 AppHelper helper = App.instance.getAppHelper();
你會編譯沒有問題。作為val,它只生成Java中的getter。如果是var,我們也會有一個setter。
因為它使用了lateinit注釋,訪問instance已經自動工作,它會自動公開Kotlin用於存儲狀態的字段。但是假設我們創建一個常數:
1 companion object { 2 lateinit var instance: App 3 val CONSTANT = 27 4 }
你會看到你不能直接訪問它。你必須通過Companion內部類訪問:
1 KotlinTest.Companion.getCONSTANT()
誰更好?要在Java中以同樣的方式暴露出一個靜態字段的方式,你需要一個新的注釋:
1 @JvmField val CONSTANT = 27
現在可以使用Java代碼:
1 int c = App.CONSTANT;
如果你在伴隨對象中有函數,則可以使用@JvmStatic注釋將其轉換為靜態方法。
結論
你看到了由Java使用Kotlin代碼非常簡單。在這里我已經展示了一些最典型的事例,其他都可以以非常相似的方式實現。
我希望如果你有任何疑問,這能夠說服你開始在項目中使用Kotlin。如果你要認真思考,我建議你閱讀這組Kotlin文章,你可以在這里了解更多關於Kotlin的信息。