Kotlin-45.Java調用kotlin之三(Call Kotlin from Java)

官方文檔: http://kotlinlang.org/docs/reference/java-to-kotlin-interop.html

8.@JvmName解決java方法簽名相同(Handling signature clashes)

最突出的例子是由于類型擦除(type erasure)引發:
    // 類型擦除: 無法區分List<String>和List<Int>
    fun List<String>.filterValid(): List<String>
    fun List<Int>.filterValid(): List<Int>
    這兩個函數在java中不能同時定義,因為它們的JVM簽名相同: filterValid(Ljava/util/List;)Ljava/util/List

在Kotlin中用相同名稱,需要用@JvmName標注其中的一個(或兩個),并指定不同名稱:
    fun List<String>.filterValid(): List<String>

    @JvmName("filterValidInt")
    fun List<Int>.filterValid(): List<Int>

    在Kotlin中,可以用相同名稱filterValid()訪問;
    在Java中,需要分別用filterValid()和filterValidInt()訪問

同樣注解@JvmName也適用于屬性x和函數getX():
    val x: Int
        @JvmName("getX_prop")
        get() = 15

    fun getX() = 10

    在Java中,需要分別用getX_prop()和getX()訪問

9.Java方法重載(Overloads Generation)

如果Kotlin函數的參數有默認值并且使用@JvmOverloads注解,
那么在Java中多個重載方法, 示例如下:
    @JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") {
    }

    // kotlin函數的每一個有默認值的參數,都會重載生成一個額外java方法:    
    void f(String a, int b, String c) {            
    }
    void f(String a, int b) {            
    }
    void f(String a) {            
    }

該注解也適用于構造函數和靜態方法, 但不能用于抽象方法(包括接口的方法)

對于次構造函數(Secondary Constructors), 如果所有參數都有默認值,
那么會生成一個公有public的無參構造函數(沒有@JvmOverloads注解也會生效)!

10.受檢異常(Checked Exception)

從前幾章《kotlin-33.異常(Exception)》可知,Kotlin沒有受檢異常!
所以Kotlin函數簽名不會聲明拋出異常(throws Exception),例如:    
    // kotlin (example.kt), 拋出異常
    package demo
    fun foo() {
        throw IOException()
    }

    // kotlin編譯生成的Java方法
    public void foo() { // 錯誤: foo()沒有聲明throws IOException
        throw IOException()
    }

因為由kotlin函數生成的Java方法foo()沒有聲明throws IOException, 所以Java編譯器報錯!
為了解決這個問題,需要在Kotlin中使用@Throws注解(相當于在Java中聲明throws IOException)
    // kotlin
    @Throws(IOException::class)
    fun foo() {
        throw IOException()
    }

    // kotlin編譯生成的Java方法
    public void foo() throws IOException {
        throw IOException()
    }

11.型變泛型(Variant generics)

當Kotlin類使用聲明處型變(declaration-site variance)時,在Java中有兩種用法!
示例:
    // kotlin
    class Box<out T>(val value: T)
    interface Base
    class Derived : Base

    fun boxDerived(value: Derived): Box<Derived>{            
    }
    fun unboxBase(box: Box<Base>): Base {            
    }
    unboxBase(boxDerived("s")) // 正確: 在Java中Box<Base>泛型是不型變的!

    // 將上述kotlin函數轉換成Java方法       
    Box<Derived> boxDerived(Derived value) {            
    }
    Base unboxBase(Box<Base> box) {            
    }
    unboxBase(boxDerived("s")) // 錯誤: 因為在Java中Box<Base>泛型是不型變的!

    //使用Java通配符類型<? extends Base>模擬kotlin聲明處型變
    Base unboxBase(Box<? extends Base> box) {            
    }
    unboxBase(boxDerived("s")) // 正確

此外, 對于協變定義的Box(在kotlin中Box<in T>), 在java中使用Box<? extends Super>
注意:當參數類型是final時,通配符? extends沒有意義,
        例如在Box<String>中的String類是final,沒有子類(不能被繼承extends)

如果在默認沒有通配符處要求java泛型通配符, 可以使用@JvmWildcard注解:
    // kotlin函數
    fun boxDerived(value: Derived): Box<@JvmWildcard Derived> {            
    }

    // 轉換成java方法 
    Box<? extends Derived> boxDerived(Derived value) {        
    }

相反,如果不需要泛型通配符,可以使用@JvmSuppressWildcards注解;
@JvmSuppressWildcards不僅可用于單個類型參數,還可用于整個聲明(如函數或類),從而抑制其中的所有通配符!
    // kotlin函數
    fun unboxBase(box: Box<@JvmSuppressWildcards Base>): Base {            
    }

    // 轉換成java方法 
    Base unboxBase(Box<Base> box) {            
    }

12.Nothing類型翻譯(Translation of type Nothing)

類型Nothing是Kotlin特有的,在Java中沒有對應類型!
每個Java引用類型(包括java.lang.Void)都接受null, 但是kotlin的Nothing不行!
Nothing類型不能在Java世界中準確表示,所以Nothing類型在java中會消失(原始類型raw type):
    // kotlin的Nothing類型
    fun emptyList(): List<Nothing> = listOf()
    
    // 翻譯成轉換成java方法, List<Nothing>變成原始類型List, Nothing類型消失了
    List emptyList() {            
    }

簡書:http://www.lxweimin.com/p/acdd8ba0830b
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/75452680
GitHub博客:http://lioil.win/2017/07/19/Kotlin-kotlinInJava3.html
Coding博客:http://c.lioil.win/2017/07/19/Kotlin-kotlinInJava3.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容