Kotlin 基础12 - Kotlin 与 Java 互操作

@JvmName

Kotlin 顶层函数在 Java 里都被当作静态方法看待和调用。

可以使用 @JvmName 注解指定编译类的名字。加到文件的最上方。

1
@file:JvmName("Hero")

@JvmOverloads

设计一个可能会暴露给 Java 用户使用的 API 时,最好使用 @JvmOverloads 注解。

这样无论是 Kotlin 开发者还是 Java 开发者,都会对这个 API 的可靠性感到满意。

1
2
3
4
5
6
7
// Hero.kt
@file:JvmName("Hero")

@JvmOverloads
fun handOverFood(leftHand: String = "berries", rightHand: String = "beef") {
println("Mmmm... you hand over some delicious $leftHand and $rightHand.")
}
1
2
3
4
// Java
Hero.handOverFood();
Hero.handOverFood("pizza");
Hero.handOverFood("pizza", "beer");

@JvmField

可以给 Kotlin 属性添加 @JvmField 注解,暴露它的支持字段给 Java 调用者,从而避免使用 getter 方法。

1
2
3
4
5
// Kotlin
class Spellbook {
@JvmField
val spells = listOf("Magic Ms. L", "Lay on Hans")
}
1
2
3
4
5
// Java
Spellbook spellbook = new Spellbook();
for (String spell : spellbook.spells) {
System.out.println(spell);
}

@JvmField 注解还能用来以静态方式提供伴生对象里定义的值。

1
2
3
4
5
6
7
// Kotlin
class Spellbook {
...
companion object {
val MAX_SPELL_COUNT = 10
}
}
1
2
// Java
Spellbook.Companion.getMAX_SPELL_COUNT();
1
2
3
4
5
6
7
8
// Kotlin
class Spellbook {
...
companion object {
@JvmField
val MAX_SPELL_COUNT = 10
}
}
1
2
// Java
System.out.println(Spellbook.MAX_SPELL_COUNT);

@JvmStatic

@JvmStatic 注解的作用类似于 @JvmField,允许直接调用伴生对象里的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Kotlin
class Spellbook {
@JvmField
val spells = listOf("Magic Ms. L", "Lay on Hans")

companion object {
@JvmField
val MAX_SPELL_COUNT = 10

@JvmStatic
fun getSpellbookGreeting() = println("I am the Great Grimoire!")
}
}
1
2
// Java
Spellbook.getSpellbookGreeting();

@Throws

Kotlin 中所有的异常都是未检查异常。对于是否要用 try/catch 语句包裹可能会导致异常的代码,Kotlin 编译器不做强制要求。

使用 @Throws 注解,Kotlin 中函数要抛出的异常就能让调用者知道。

注解给 Java 版本的函数添加了一个 throws 关键字。

1
2
3
4
@Throws(IOException::class)
fun acceptApology() {
throw IOException()
}

Java 中的函数类型

Java 8 之前的 JDK 版本并不支持 lambda 表达式。

在 Java 里,Kotlin 函数类型是用 FunctionN 这样的名字的接口来表示的,FunctionN 中的 N 代表值参数目。

1
2
3
val translator = { utterance: String ->
println(utterance.toLowerCase().capitalize())
}
1
2
3
4
5
6
7
import kotlin.Unit;
import kotlin.jvm.functions.Function1;

...

Function1<String, Unit> translator = Hero.getTranslator();
translator.invoke("TRUCE");