實(shí)際開發(fā)我們即使決定切換到Kotlin語言,但由于歷史模塊或依賴的第三方庫仍是使用Java開發(fā)的,這也就不可避免在二者之前產(chǎn)生相互調(diào)用,雖然官方宣稱100%兼容,但實(shí)際使用過程中仍有一些小問題需要注意。
Kotlin調(diào)用Java
get/set方法
由于Kotlin中并不需要顯式的聲明get/set方法,所以對于訪問Java標(biāo)準(zhǔn)實(shí)體類中的屬性,可直接通過屬性名稱。
Animal.java
public class Animal {
private int age;
private String name;
public Animal(int age, String name) {
this.age = age;
this.name = name;
}
//...getter/setter
}
kotlin中這樣使用
val animal = Animal(3, "twodog")
println(animal.age)//讀取
animal.name = "dahuang"http://修改
獲取Java類型
若想獲取某個(gè)java類的類型需通過Kotlin的反射實(shí)現(xiàn)。::得到Kotlin類型,繼續(xù)調(diào)用擴(kuò)展屬性java得到其對應(yīng)的java類型。
val animal = Animal(3, "twodog")
println(animal::class.java.simpleName)
//輸出
Animal
wait/notify
我們知道kotlin中Any與Java中的Object對應(yīng),但問題是Any類中只有equals/hashCode/toString三個(gè)方法。
public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
那并發(fā)編程用到的等待喚醒wait/notify方法如何使用呢?事實(shí)上官方不建議使用普通對象鎖,取而代之的是Lock鎖。如果你確實(shí)想使用可以通過下面的方法。
(foo as java.lang.Object).wait()
即先強(qiáng)轉(zhuǎn)為java的Object類型,再使用并發(fā)函數(shù)。
Java調(diào)用Kotlin
get/set方法
java訪問Kotlin的屬性應(yīng)使用對用的getter/setter方法。
//Client.kt
data class Client(var name: String)
//java test
Client client = new Client("zhangsan");
System.out.println(client.getName());
client.setName("lisi");
另外,Kotlin中默認(rèn)會(huì)給屬性添加getter/setter方法(val類型的沒有setter),這勢必會(huì)造成一定的性能損耗,可為屬性添加@JvmField注解去掉此默認(rèn)行為。
//去掉NO屬性的getter/setter
data class Client(var name: String,@JvmField var NO: Int)
頂級函數(shù)
之前章節(jié)講到頂級函數(shù)是用靜態(tài)方法實(shí)現(xiàn)的,而該靜態(tài)方法所在的類為kotlin文件名+Kt。
// TestPackageMethod.kt
fun sayHello(name: String) {
println("hello $name")
}
//java test
TestPackageMethodKt.sayHello("zhao");
如果想改變生成的默認(rèn)類名,可以在kt文件中package聲明前添加注解。
//改變默認(rèn)生成的Java類名
@file:JvmName("MyPackageMethodTest")
object靜態(tài)函數(shù)
之前講到object類為單例類,內(nèi)部實(shí)現(xiàn)是通過餓漢式實(shí)現(xiàn)單例,在類中有一個(gè)本類的靜態(tài)實(shí)例,因此當(dāng)在java中訪問此object類中方法的時(shí)需通過此靜態(tài)實(shí)例,該實(shí)例的默認(rèn)名字統(tǒng)一為INSTANCE。
//ObjectTest.kt
object ObjectTest {
fun objectMethod() {
}
}
//java call
ObjectTest.INSTANCE.objectMethod();
伴生對象
伴生對象同樣是通過靜態(tài)實(shí)現(xiàn),只不過靜態(tài)方法在一個(gè)Companion內(nèi)部類中,因此Java調(diào)用需顯示聲明Companion類名。
//TestStatic.kt
open class TestStatic {
companion object {
fun create(): TestStatic {
return TestStatic()
}
}
}
//java call
TestStatic.Companion.create()
異常檢查
與Java語言非常大的不同是Kotlin不做異常檢查,這就導(dǎo)致在Java中聲明的檢查異常不需在Kotlin代碼中捕獲,從而發(fā)生意想不到的崩潰,反之亦然。
//TestKotlinException.kt
object TestKotlinException {
//拋出異常但方法不需異常聲明
fun getException() {
throw Exception("I am an exception in kotlin")
}
}
//java call
public static void testException() {
//編譯通過 但運(yùn)行會(huì)發(fā)生異常
TestKotlinException.INSTANCE.getException();
}
如果想改變此默認(rèn)行為,我們需要在Kotlin方法前添加@Throws(Exception::class)注解。
@Throws(Exception::class)
fun getException() {
throw Exception("I am an exception in kotlin")
}
此時(shí)java調(diào)用端會(huì)出現(xiàn)期望的編譯錯(cuò)誤。
//unhandled exception: java.lang.Exception
TestKotlinException.INSTANCE.getException();