Java 与 Kotlin 互操作

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 不会强迫做任何事情。

Java 反射

我们可以使用 instance::class.java
,

ClassName::class.java
或者 instance.javaClass
通过 java.lang.Class
来进入 Java 反射。

SAM 转换

就像 Java 8 一样,Kotlin 支持 SAM 转换。这意味着 Kotlin 函数字面值可以被自动的转换成只有一个非默认方法的 Java 接口的实现,只要这个方法的参数类型能够与这个 Kotlin 函数的参数类型相匹配。

val runnable = Runnable { println("This runs in a runnable") }

请注意,SAM 转换只适用于接口,而不适用于抽象类,即使这些抽象类也只有一个抽象方法。还要注意,此功能只适用于 Java 互操作;因为 Kotlin 具有合适的函数类型,所以不需要将函数自动转换为 Kotlin 接口的实现,因此不受支持。

Java 中调用 Kotlin

属性

如果属性的名称以 is
开头,则使用不同的名称映射规则:getter 的名称与属性名称相同,并且 setter 的名称是通过将 is
替换为 set
获得。例如,对于属性 isOpen
,其 getter 会称做 isOpen()
,而其 setter 会称做 setOpen()

这一规则适用于任何类型的属性,并不仅限于 Boolean

常用注解 @JvmName

这里,会编译成一个名为 org.foo.bar.ExampleKt
的 Java 类的静态方法。我们通过 @file:JvmName("DemoUtils")
指定类名。

@file:JvmName("DemoUtils")

package demo

class Foo

fun bar() {
}
// Java
new demo.Foo();
demo.DemoUtils.bar();

常用注解 @JvmField

如果需要在 Java 中将 Kotlin 属性作为字段暴露,那就需要使用 @JvmField
注解对其标注。该字段将具有与底层属性相同的可见性。

class C(id: String) {
    @JvmField val ID = id
}
// Java
class JavaClient {
    public String getID(C c) {
        return c.ID;
    }
}

常用注解 @JvmStatic

Kotlin 还可以为命名对象或伴生对象中定义的函数生成静态方法,如果你将这些函数标注为 @JvmStatic
的话。如果你使用该注解,编译器既会在相应对象的类中生成静态方法,也会在对象自身中生成实例方法。

class C {
    companion object {
        @JvmStatic fun foo() {}
        fun bar() {}
    }
}

现在, foo()
在 Java 中是静态的:

C.foo(); // 没问题
C.Companion.foo(); // 保留实例方法

@JvmStatic
注解也可以应用于对象或伴生对象的属性,使其 getter 和 setter 方法在该对象或包含该伴生对象的类中是静态成员。

常用注解 @JvmOverloads

如果我们写一个有默认参数值的 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()
}

NoArg 和 AllOpen

在 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>

原文 

http://blog.720ui.com/2018/kotlin_04_java/

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Java 与 Kotlin 互操作

分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址