Kotlin での Java レコードの使用
レコード(Records)は、不変(immutable)のデータを格納するための Java のクラスです。レコードは、レコードコンポーネント(records components)と呼ばれる固定された値のセットを保持します。 Java では簡潔な構文を持ち、ボイラープレートコードを書く手間を省くことができます。
// Java
public record Person (String name, int age) {}コンパイラは、java.lang.Record を継承した final クラスを自動的に生成し、以下のメンバーを含めます:
- 各レコードコンポーネントに対する private final フィールド
- すべてのフィールドを引数に持つ public コンストラクタ
- 構造的な等価性を実装するためのメソッド群:
equals()、hashCode()、toString() - 各レコードコンポーネントを読み取るための public メソッド
レコードは Kotlin のデータクラスに非常によく似ています。
Kotlin コードからの Java レコードの使用
Java で宣言されたコンポーネントを持つレコードクラスは、Kotlin のプロパティを持つクラスと同じように使用できます。 レコードコンポーネントにアクセスするには、Kotlin のプロパティと同じように、その名前を使用するだけです:
val newPerson = Person("Kotlin", 10)
val firstName = newPerson.nameKotlin でのレコードの宣言
Kotlin ではデータクラスに対してのみレコードの宣言をサポートしており、そのデータクラスは要件を満たしている必要があります。
Kotlin でレコードクラスを宣言するには、@JvmRecord アノテーションを使用します:
既存のクラスに
@JvmRecordを適用することは、バイナリ互換性のある変更ではありません。クラスプロパティのアクセサの命名規則が変更されます。
@JvmRecord
data class Person(val name: String, val age: Int)この JVM 固有のアノテーションにより、以下が生成されるようになります:
- クラスファイル内でのクラスプロパティに対応するレコードコンポーネント
- Java レコードの命名規則に従って命名されたプロパティアクセサメソッド
データクラスは equals()、hashCode()、および toString() メソッドの実装を提供します。
要件
@JvmRecord アノテーションを使用してデータクラスを宣言するには、以下の要件を満たす必要があります:
- クラスは JVM 16 バイトコード(または
-Xjvm-enable-previewコンパイラオプションが有効な場合は 15)をターゲットとするモジュール内にある必要があります。 - すべての JVM レコードは暗黙的に
java.lang.Recordを継承するため、クラスは他のクラス(Anyを含む)を明示的に継承することはできません。ただし、インターフェースを実装することは可能です。 - クラスは、対応するプライマリコンストラクタのパラメータから初期化されるものを除き、バッキングフィールドを持つプロパティを宣言することはできません。
- クラスは、バッキングフィールドを持つ可変(mutable)プロパティを宣言することはできません。
- クラスをローカルクラスにすることはできません。
- クラスのプライマリコンストラクタは、そのクラス自身と同じ可視性である必要があります。
JVM レコードの有効化
JVM レコードには、生成される JVM バイトコードのターゲットバージョン 16 以上が必要です。
これを明示的に指定するには、Gradle または Maven で jvmTarget コンパイラオプションを使用します。
Kotlin でのレコードコンポーネントへのアノテーション付与
Java では、レコードコンポーネントに対するアノテーションは、バッキングフィールド、ゲッター、セッター、およびコンストラクタパラメータに自動的に伝播されます。 all 使用箇所ターゲット(use-site target)を使用することで、Kotlin でもこの動作を再現できます。
all使用箇所ターゲットを使用するには、オプトインが必要です。-Xannotation-target-allコンパイラオプションを使用するか、build.gradle.ktsファイルに以下を追加してください。kotlinkotlin { compilerOptions { freeCompilerArgs.add("-Xannotation-target-all") } }
例えば:
@JvmRecord
data class Person(val name: String, @all:Positive val age: Int)@JvmRecord を @all: と併用すると、Kotlin は以下を行います:
- アノテーションをプロパティ、バッキングフィールド、コンストラクタパラメータ、ゲッター、セッターに伝播させます。
- アノテーションが 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 レコードに関する言語提案 を参照してください。
