Your Site Title

kotlin jvm

kotlin多平台开发支持:

Comparison to java

Some Java issues addressed in Kotlin:

What Java has that Kotlin does not:

What Kotlin has that Java does not:

Calling Java from Kotlin

Java几乎所有的代码都可以在kotlin中使用.

Getters and setters

Java getters and setters 会转换成kotlin get 和 set 方法. Java对象属性如果只有set方法, 那么kotlin不支持.

Methods returning void

void -> unit

Escaping for Java identifiers that are keywords in Kotlin

调用java标识符是kotlin关键字, 使用”". foo.is`(bar)

Null-safety and platform types

kotlin会对Java平台声明的类型做特殊处理, 称为平台类型. kotlin对平台类型不会有编译时非空检查, 但是会有运行时空指针异常或kotlin为防止空值的 断言 平台类型是不可表示的, 当kotlin非空引用一个Java对象, kotlin会产生一具非空断言, 保证 对象不为空

平台类型助记符:

为空性注释:

-Xnullability-annotations=@<package-name>:<report-level> 可以检查 report-level

Mapped types

Mapped types

Java generics in Kotlin

Java’s wildcards are converted into type projections:

Foo<? extends Bar> becomes Foo<out Bar!>!

Foo<? super Bar> becomes Foo<in Bar!>!

Java’s raw types are converted into star projections:

List becomes List<*>! that is List<out Any?>!

Java arrays

kotlin数组是不变的, 不像Java是协变的. kotlin可以使用Array<(out) String>! kotlin数组使用java数组实现, 并提供IntArray, DoubleArray, CharArray

Java varargs

kotlin调用java传递可变长度参数时, 数组需要使用*解构

Operators

kotlin允许操作符重载, 不允许使用中缀操作符调用Java方法.

checked exceptions

kotlin中没有检查异常, 调用Java方法中如果有检查异常, 也不需要处理.

Object methods

当Java类型进入到kotlin时, java.lang.Object会转换成Any Any中只有toString, hashCode, equals

调用wait()/notify()
(foo as java.lang.Object).wait()

getClass()
val fooClass = foo::class.java
val fooClass = foo.javaClass

clone() // kotlin需要扩展`kotlin.Cloneable`
class Example : Cloneable {
    override fun clone(): Any { ... }
}

finalize() // 不使用`override`关键字重写`finalize`方法, 不能为`private`
class C {
    protected fun finalize() {
        // finalization logic
    }
}

Inheritance from Java classes

可以实现一个Java类, 多个Java接口

Accessing static members

Java中静态成员转换成了companion objects, 不能当值传递, 可以显示访问. 访问映射到Kotlin类型的Java类型的静态成员, 需要Java完整签名java.lang.Integer.bitCount(foo)

Java reflection

引用Java类 instance::class.java instance.javaClass

引用伴生类 ClassName::class.java 相当于下面 ClassName.Companion::class.java

SAM conversions

kotlin支持 SAM 在Java和kotlin间转换. 只支持接口, 不支持抽象类 如果需要调用Java重载方法, 可以将lambada转换成特定的SAM类型, 适配调用方法.

executor.execute(Runnable { println("This runs in a thread pool") })

Using JNI with Kotlin

使用external声明调用本地方法的函数, 其它的与Java中相同 还可以修改getter和setter方法,

var myProperty: String
    external get
    external set

映射到getMyProperysetMyProperty

Using Lombok-generated declarations in Kotlin

Lombok compiler plugin

Calling Kotlin from Java

Properties

如果属性是is开头如isOpen, getter为isOpen(), setter使用set替换is成setOpen

Package-level function

使用Kotlin文件名包名 + 文件名引用

// app.kt
package org.example

class Util

fun getTime() { /*...*/ }

// Java
new org.example.Util();
org.example.AppKt.getTime();

使用@JvmName自定义生成Java类的名称

@file:JvmName("DemoUtils")

package org.example

class Util

fun getTime() { /*...*/ }

// Java
new org.example.Util();
org.example.DemoUtils.getTime();

顶级签名需要唯一, 但可以使用@file:JvmMultifileClass生成facade, facade包含相同签名的顶级文件.

Instance fields

@JvmField可以将Kotlin属性作为Java中字段公开. 必须满足:

Late-initialized 属性也是公开字段, 可见性与setter相同. Late-initialized 会有static backing field

Static fields

named objectCompanion object中声明的属性是私有的, 可以使用下列方式公开:

Static methods

kotlin会把顶级函数编译成静态对象, 使用@JvmStatic修饰, 可以使 named objectscompanion objects 方法成静态方法. 编译器会生成静态方法和实例方法.

class C {
    companion object {
        @JvmStatic fun callStatic() {}
        fun callNonStatic() {}
    }
}

callStatic 是静态的, callNonStatic不是的

C.callStatic(); // works fine
C.callNonStatic(); // error: not a static method
C.Companion.callStatic(); // instance method remains
C.Companion.callNonStatic(); // the only way it works

1.3支持接口伴生对象方法声明@JvmStatic, 1.8支持接口方法声明@JvmStatic

Default methods in interfaces

JDK1.8支持接口默认方法, -Xjvm-default=all把kotlin接口中所有非抽象方法编译成 Java默认方法.

kotlin1.4前使用@JvmDefault注释默认方法, 1.4后使用-Xjvm-default=all, 这二种生 成的二进制代码不兼容. 可以使用@JvmDefaultWithCompatibility注解在接口上实现兼容.

kotlin 1.6.20 支持-Xjvm-default=disable(默认), -Xjvm-default=all, -Xjvm-default=all-compatibility

Visibility

KClass

手动Java类转kotlin类

kotlin.jvm.JvmClassMappingKt.getKotlinClass(MainView.class)

Handling signature clashes with @JvmName

kotlin指定生成JVM函数签名, 使用@JvmName

fun List<String>.filterValid(): List<String>

@JvmName("filterValidInt")
fun List<Int>.filterValid(): List<Int>

@get:JvmName("x")
@set:JvmName("changeX")
var x: Int = 23

Overloads generation

Java函数重载, kotlin中使用参数默认值. 在Java中调用kotlin参数默认值, 所有参数都 需要传递.

Kotlin参数默认值, 如果想生成Java函数重载, 使用@JvmOverloads

class Circle @JvmOverloads constructor(centerX: Int, centerY: Int, radius: Double = 1.0) {
    @JvmOverloads fun draw(label: String, lineWidth: Int = 1, color: String = "red") { /*...*/ }
}

Checked exceptions

kotlin中没有检查异常, 如果需要Java调用kotlin时显示检查异常, 使用@Throws

@Throws(IOException::class)
fun writeToFile() {
    /*...*/
    throw IOException()
}

Null-safety

kotlin会对所有公式函数显示的运行时检查非空参数. java调用kotlin, 如果传null, 会得到NPE.

Variant generics

kotlin编译器会判断代码, 在需要通配符的地方, 生成对应的Java函数. 如果需要在没有生成通配符的地址生成, 使用@JvmWildcard. 生成的地方不需要, 使用@JvmSuppressWildcards.

Translation of type Nothing

Noting在Java中没有表示, 包括java.lang.Void

Using Java records in Kotlin

JDK14 支持 record class. 一组不变值的类, 可以不生成样板代码.

// Java
public record Person (String name, int age) {}

// kotlin
val newPerson = Person("Kotlin", 10)
val firstName = newPerson.name

kotlin中使用record, 使用@JvmRecord

@JvmRecord
data class Person(val name: String, val age: Int)

将现有的类声明为record, 不是二进制兼容的. 需要JDK 16

Reference

Kotlin/JVM