Kotlin 与 Java 的互操作性

在 Kotlin 中调用 Java

一个简单的例子

废话不多说,直接上代码:

1
2
3
4
5
6
7
8
9
10
import java.util.*

fun callJava (source: List<Int>) {
val list = ArrayList<Int>()

// 对 Java 集合使用 for 循环
for (item in source) {
list.add(item)
}
}

Getter 和 Setter

在 Java 中的 get 和 set 方法,在 Kotlin 中会被识别为属性,如:

1
2
3
4
5
6
7
8
9
10
import java.util.Calendar

fun calendarDemo() {
val calendar = Calendar.getInstance()
// 下面等同于 calendar.getFirstDayOfWeek() == Calendar.SUNDAY
if (calendar.firstDayOfWeek == Calendar.SUNDAY) {
// 下面等同于 calendar.setFirstDayOfWeek(Calendar.MONDAY)
calendar.firstDayOfWeek = Calenar.MONDY
}
}

返回值为 void 的方法

如果一个 java 方法的返回值为 void,那么在 Kotlin 中调用时将返回 Unit。

对 Kotlin 的关键字进行转义

某些 Kotlin 关键字在 Java 中是合法的标识符:in, object, is, 等等。如果 Java 类库中使用 Kotlin 的关键字作为方法名,你仍然可以调用这个方法,只要使用反引号(`)对方法名转义即可:

1
foo.`is`(bar)

Null 值安全性

在 Java 中,所用引用类型的值都可以为 null,因此,对于 java 中对象,Kotlin 的严格空类型检查将变得毫无意义,为了保证同 java 的兼容性,Kotlin 使用了一种助记符(!)来表标识一个可空可非空的类型。如 T! 代表 T 或者 T?

使用 Java 泛型

Kotlin 的泛型与 Java 的泛型略有差异。将 Java 类型导入 Kotlin 时,我们需要进行变换:

Java 泛型 Kotlin 泛型
Foo<? extends Bar> Foo<out Bar!>!
Foo<? super Bar> Foo<in Bar!>!
List List<*>! 或者 List<out Any?>!

Java 的可变长参数

Java 类的方法声明有时使用可变长参数(Varargs):

1
2
3
4
5
public class JavaDemo {
public void foo (int... indices) {

}
}

在这种情况下,在 Kotlin 中调用时需要使用展开操作符(spread)*

1
2
val array = intArrayOf(0, 1, 2, 3)
JavaDemo.foo(*array)

Java 中的 Object

Java 中所用的 java.lang.Object 类型在 Kotlin 中都将会转换为 Any 类型。由于 Any 类与具体的平台实现无关,因此它声明的成员方法只有 toString(), hashCode()equals()

getClass()

  • 要得到一个对象的类型信息,我们可以使用 Any 类的扩展属性 javaClass
  • 要得到一个类的类型信息,我们可以使用T::class.java,而不是 Java 中的 T.class
1
2
val fooClass = foo.javaClass
val barClass = Bar::class.java

clone()

要覆盖 clone() 方法,你必须实现一个 kotlin.Cloneable 接口。

1
2
3
4
5
class Demo : Cloneable {
override fun clone():Any {

}
}

finalize()

要覆盖 finalize() 方法,你只需要声明它即可,不必使用 override 关键字。

1
2
3
4
5
class Demo {
protected fun finalize () {

}
}

在 Java 中调用 Kotlin

访问属性

在 Java 中,对属性的访问会被转换成对应的 getter 和 setter 方法。

包级函数

通过默认类名访问

默认情况下,在 Kotlin 源码中所有的包级函数和属性,你可以在 Java 中通过对应包下的 “文件名Kt” 类中访问到。

1
2
3
4
5
6
// 假设文件名为 Example.kt
package demo

fun foo () {

}
1
demo.ExampleKt.foo();

通过自定义类名访问

你也可以通过 @file:JvmName 注解来指定生成的类名

1
2
3
4
5
6
7
@file:JvmName("DemoUtils")

package demo

fun bar() {

}
1
demo.DemoUtils.bar();

将自定义类名进行合并

当你在相同包名下的两个不同文件中,使用 @file:JvmName 注解指定了相同的类名时,你可以使用 @file:JvmMultifileClass 来生成单个的 Java Facade 类。

1
2
3
4
5
6
7
8
@file:JvmName("Utils")
@file:JvmMultifileClass

package demo

fun foo() {

}
1
2
3
4
5
6
7
8
@file:JvmName("Utils")
@file:JvmMultifileClass

package demo

fun bar() {

}
1
2
demo.Utils.foo();
demo.Utils.bar();

参考