在 Kotlin 中使用 Java 记录类(Record)
在 Java 中 记录类(Record) 是用于存储不可变数据的 类. 记录类携带一组固定的值 – 记录组件(Records Components). 在 Java 中记录类的语法很简洁, 可以为你省去编写样板代码的时间:
// Java
public record Person (String name, int age) {}
编译器会自动生成一个 final 类, 继承自 java.lang.Record
, 并包含以下成员:
对每个记录组件, 有一个 private final 域
一个 public 构造器, 参数是所有的域
一组方法, 实现结构化的相等比较:
equals()
,hashCode()
,toString()
为读取每个记录组件, 有一个 public 方法
记录类非常类似于 Kotlin 数据类.
在 Kotlin 中, 你可以通过使用类和属性相同的方式来使用 Java 中声明的记录类及其组件. 要访问记录组件, 可以和使用 Kotlin 属性 一样, 直接使用它的名称:
val newPerson = Person("Kotlin", 10)
val firstName = newPerson.name
Kotlin 只支持对数据类声明记录类, 而且数据类必须符合 要求.
要在 Kotlin 中声明一个数据类, 请使用 @JvmRecord
注解:
note
向一个已存在的类添加
@JvmRecord
, 这样的变化会导致二进制不兼容. 会改变类属性访问器的命名规约.
@JvmRecord
data class Person(val name: String, val age: Int)
这个 JVM 专用的注解会导致生成以下内容:
在 class 文件中, 生成与类属性对应的记录组件
符合 Java 记录类命名规约的类属性访问器方法名
数据类会提供 equals()
, hashCode()
, 和 toString()
方法的实现.
要使用 @JvmRecord
注解来声明数据类, 它必须符合以下要求:
类所在模块的编译目标必须是 JVM 16 字节码 (或者 JVM 15, 并开启
-Xjvm-enable-preview
编译器选项).类不能明确继承任何其他类 (包括
Any
), 因为所有的 JVM 记录类都要隐含的继承java.lang.Record
. 但是, 类可以实现接口.类不能声明任何带有后端域(Backing Field)的属性 – 通过主构造器参数初始化的对应属性除外.
类不能声明任何带有后端域(Backing Field)的可变属性.
不能是局部(local)类.
类的主构造器的可见度必须与类本身相同.
对生成的 JVM 字节码, JVM 记录类要求的编译目标为 16
或更高版本.
在 Java 中, 记录组件上的 注解 会自动传递到后端域变量(Backing Field), 取值方法(Getter), 设值方法(Setter), 以及构造器参数. 在 Kotlin 中, 你可以通过 all
使用目标(Use-site Target)来复制这个动作.
warning
要使用
all
使用目标, 你需要标注使用者同意. 可以使用-Xannotation-target-all
编译器选项, 或者向你的build.gradle.kts
文件添加以下内容:kotlin { compilerOptions { freeCompilerArgs.add("-Xannotation-target-all") } }
例如:
@JvmRecord
data class Person(val name: String, @all:Positive val age: Int)
当你将 @JvmRecord
和 @all:
一起使用时, Kotlin 会:
将注解传递到属性, 后端域变量(Backing Field), 构造器参数, 取值方法(Getter)和设值方法(Setter).
如果注解支持 Java 的
RECORD_COMPONENT
, 还会将注解应用到记录组件.
要让一个 注解 能够同时用于 Kotlin 属性 和 Java 记录组件, 请向你的注解声明添加以下元注解:
对 Kotlin:
@Target
对 Java 记录组件:
@java.lang.annotation.Target
例如:
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@java.lang.annotation.Target(ElementType.CLASS, ElementType.RECORD_COMPONENT)
annotation class ExampleClass
现在 @ExampleClass
可以用于 Kotlin 类和属性, 也可以用于 Java 类和记录组件.
关于更多技术细节和讨论, 请参见 对 JVM 记录类的语言规格建议.