Java 声明的类型在 Kotlin 中会被特别对待并称为 平台类型 。Kotlin 对这种类型的空检查会放宽,当我们调用平台类型变量的方法时,Kotlin 不会在编译时抛出 NullPointerException 异常。
这里,我们可以使用 Lombok( lombok.NonNull
)或 JSR-305( javax.annotation
)进行可空性注解,尽量防止抛出 NullPointerException 异常。
遵循 Java 约定的 getter 和 setter 的方法(名称以 get
开头的无参数方法和以 set
开头的单参数方法)在 Kotlin 中表示为属性。 Boolean
访问器方法(其中 getter 的名称以 is
开头而 setter 的名称以 set
开头)会表示为与 getter 方法具有相同名称的属性。请注意,如果 Java 类只有一个 setter,它在 Kotlin 中不会作为属性可见,因为 Kotlin 目前不支持只写(set-only)属性。
在 Kotlin 中,所有异常都是非受检的,因此编译器不会强迫捕获其中的任何一个。因此,当你调用一个声明受检异常的 Java 方法时,Kotlin 不会强迫做任何事情。
我们可以使用 instance::class.java
,
ClassName::class.java
或者 instance.javaClass
通过 java.lang.Class
来进入 Java 反射。
就像 Java 8 一样,Kotlin 支持 SAM 转换。这意味着 Kotlin 函数字面值可以被自动的转换成只有一个非默认方法的 Java 接口的实现,只要这个方法的参数类型能够与这个 Kotlin 函数的参数类型相匹配。
val runnable = Runnable { println("This runs in a runnable") }
请注意,SAM 转换只适用于接口,而不适用于抽象类,即使这些抽象类也只有一个抽象方法。还要注意,此功能只适用于 Java 互操作;因为 Kotlin 具有合适的函数类型,所以不需要将函数自动转换为 Kotlin 接口的实现,因此不受支持。
如果属性的名称以 is
开头,则使用不同的名称映射规则:getter 的名称与属性名称相同,并且 setter 的名称是通过将 is
替换为 set
获得。例如,对于属性 isOpen
,其 getter 会称做 isOpen()
,而其 setter 会称做 setOpen()
。
这一规则适用于任何类型的属性,并不仅限于 Boolean
。
这里,会编译成一个名为 org.foo.bar.ExampleKt
的 Java 类的静态方法。我们通过 @file:JvmName("DemoUtils")
指定类名。
@file:JvmName("DemoUtils") package demo class Foo fun bar() { }
// Java new demo.Foo(); demo.DemoUtils.bar();
如果需要在 Java 中将 Kotlin 属性作为字段暴露,那就需要使用 @JvmField
注解对其标注。该字段将具有与底层属性相同的可见性。
class C(id: String) { @JvmField val ID = id }
// Java class JavaClient { public String getID(C c) { return c.ID; } }
Kotlin 还可以为命名对象或伴生对象中定义的函数生成静态方法,如果你将这些函数标注为 @JvmStatic
的话。如果你使用该注解,编译器既会在相应对象的类中生成静态方法,也会在对象自身中生成实例方法。
class C { companion object { @JvmStatic fun foo() {} fun bar() {} } }
现在, foo()
在 Java 中是静态的:
C.foo(); // 没问题 C.Companion.foo(); // 保留实例方法
@JvmStatic
注解也可以应用于对象或伴生对象的属性,使其 getter 和 setter 方法在该对象或包含该伴生对象的类中是静态成员。
如果我们写一个有默认参数值的 Kotlin 函数,在 Java 中只会有一个所有参数都存在的完整参数签名的方法可见,如果希望向 Java 调用者暴露多个重载,可以使用 @JvmOverloads
注解。该注解也适用于构造函数、静态方法等。它不能用于抽象方法,包括在接口中定义的方法。
class Foo @JvmOverloads constructor(x: Int, y: Double = 0.0) { @JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") { …… } }
对于每一个有默认值的参数,都会生成一个额外的重载,这个重载会把这个参数和它右边的所有参数都移除掉。在上例中,会生成以下代码:
// 构造函数: Foo(int x, double y) Foo(int x) // 方法 void f(String a, int b, String c) { } void f(String a, int b) { } void f(String a) { }
Kotlin 没有受检异常。所以,通常 Kotlin 函数的 Java 签名不会声明抛出异常。为了解决这个问题,要在 Kotlin 中使用 @Throws
注解。
@Throws(IOException::class) fun foo() { throw IOException() }
在 Kotlin 中,data class 默认没有无参构造方法,并且 data class 默认为 final 类型,不可以被继承。注意的是,如果我们使用 Spring + Kotlin 的模式,那么使用 @autowared 就可能遇到这个问题。因此,我们可以添加 NoArg 为标注的类生成无参构造方法。使用 AllOpen 为被标注的类去掉 final,允许被继承。
<dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-noarg</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies>