Kotlin基本语法之(九)Kotlin与java互操作
实际开发我们即使决定切换到Kotlin语言,但由于历史模块或依赖的第三方库仍是使用Java开发的,这也就不可避免在二者之前产生相互调用,虽然官方宣称100%兼容,但实际使用过程中仍有一些小问题需要注意。
Kotlin调用Java
get/set方法
由于Kotlin中并不需要显式的声明get/set方法,所以对于访问Java标准实体类中的属性,可直接通过属性名称。
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"//修改
获取Java类型
若想获取某个java类的类型需通过Kotlin的反射实现。::
得到Kotlin类型,继续调用扩展属性java得到其对应的java类型。
val animal = Animal(3, "twodog")
println(animal::class.java.simpleName)
//输出
Animal
wait/notify
我们知道kotlin中Any与Java中的Object对应,但问题是Any类中只有equals/hashCode/toString三个方法。
public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
那并发编程用到的等待唤醒wait/notify方法如何使用呢?事实上官方不建议使用普通对象锁,取而代之的是Lock锁。如果你确实想使用可以通过下面的方法。
(foo as java.lang.Object).wait()
即先强转为java的Object类型,再使用并发函数。
Java调用Kotlin
get/set方法
java访问Kotlin的属性应使用对用的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中默认会给属性添加getter/setter方法(val类型的没有setter),这势必会造成一定的性能损耗,可为属性添加@JvmField注解去掉此默认行为。
//去掉NO属性的getter/setter
data class Client(var name: String,@JvmField var NO: Int)
顶级函数
之前章节讲到顶级函数是用静态方法实现的,而该静态方法所在的类为kotlin文件名+Kt。
// TestPackageMethod.kt
fun sayHello(name: String) {
println("hello $name")
}
//java test
TestPackageMethodKt.sayHello("zhao");
如果想改变生成的默认类名,可以在kt文件中package声明前添加注解。
//改变默认生成的Java类名
@file:JvmName("MyPackageMethodTest")
object静态函数
之前讲到object类为单例类,内部实现是通过饿汉式实现单例,在类中有一个本类的静态实例,因此当在java中访问此object类中方法的时需通过此静态实例,该实例的默认名字统一为INSTANCE
。
//ObjectTest.kt
object ObjectTest {
fun objectMethod() {
}
}
//java call
ObjectTest.INSTANCE.objectMethod();
伴生对象
伴生对象同样是通过静态实现,只不过静态方法在一个Companion内部类中,因此Java调用需显示声明Companion类名。
//TestStatic.kt
open class TestStatic {
companion object {
fun create(): TestStatic {
return TestStatic()
}
}
}
//java call
TestStatic.Companion.create()
异常检查
与Java语言非常大的不同是Kotlin不做异常检查,这就导致在Java中声明的检查异常不需在Kotlin代码中捕获,从而发生意想不到的崩溃,反之亦然。
//TestKotlinException.kt
object TestKotlinException {
//抛出异常但方法不需异常声明
fun getException() {
throw Exception("I am an exception in kotlin")
}
}
//java call
public static void testException() {
//编译通过 但运行会发生异常
TestKotlinException.INSTANCE.getException();
}
如果想改变此默认行为,我们需要在Kotlin方法前添加@Throws(Exception::class)
注解。
@Throws(Exception::class)
fun getException() {
throw Exception("I am an exception in kotlin")
}
此时java调用端会出现期望的编译错误。
//unhandled exception: java.lang.Exception
TestKotlinException.INSTANCE.getException();