官方文檔: 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