Kotlinのバッキングフィールド
1. 概要
このクイックチュートリアルでは、Kotlinでのバッキングフィールドとそのユースケースについて理解します。
まず、Kotlinのプロパティとカスタムアクセサーについて簡単に紹介します。 次に、カスタムアクセサの例でバッキングフィールドを使用します。 最後に、バッキングフィールドがバイトコードレベルでどのように実装されているかを確認します。
2. バッキングフィールド
Kotlinは、可変または不変のプロパティの宣言をサポートしています。 プロパティをvalまたはvarでマークするだけです。
data class HttpResponse(val body: String, var headers: Map<String, String>)
上記の例では、Kotlinコンパイラは body プロパティのゲッターを生成し、headersプロパティのゲッターとセッターの両方を生成します。 内部的には、KotlinはJavaフィールドを使用してプロパティ値を格納します。 これらのJavaフィールドは、Kotlinの世界ではバッキングフィールドとして知られています。
ただし、ロジックを制御するためにカスタムアクセサーを作成する必要がある場合もあります。 たとえば、ここでは、 hasBody プロパティの簡単なゲッターを作成しています。
data class HttpResponse(val body: String, var headers: Map<String, String>) {
val hasBody: Boolean
get() = body.isNotBlank()
}
hasBody のゲッターは、本体が空白の場合、trueを返します。 KotlinはbodyプロパティからhasBody値を計算できるため、そのバッキングフィールドは生成されません。
ここで、指定された値が100〜599の場合にのみ、statusCodeプロパティを設定するとします。 最初の試みでは、次のようなことを試みる可能性があります。
var statusCode: Int = 100
set(value) {
if (value in 100..599) statusCode = value
}
statusCode プロパティを設定するたびに、Kotlinは set(value)カスタムアクセサーを呼び出します。 このフィールドもセッター自体の内部に設定しているため、現在の実装は無限の再帰呼び出しです。
この無限の再帰を回避するために、Kotlinがこのプロパティに対して生成するバッキングフィールドを使用できます:
var statusCode: Int = 100
set(value) {
if (value in 100..599) field = value
}
上に示したように、プロパティにバッキングフィールドが必要な場合、Kotlinはそれを自動的に提供します。 さらに、フィールド識別子を介してカスタムアクセサー内のバッキングフィールドを参照できます。
簡単に言えば、バッキングフィールドはプロパティの値が格納される場所です。 最後の例では、バッキングフィールドが再帰の問題を回避するのに役立ちました。
3. バイトコード表現
Kotlinは、少なくとも1つのデフォルトアクセサーを使用するか、カスタムアクセサー内でフィールド識別子を参照する場合、プロパティのバッキングフィールドを生成します。 デフォルトのアクセサーは、valまたはvarキーワードで生成されたアクセサーです。
このステートメントを検証するために、生成されたバイトコードを確認できます。 まず、kotlincを使用してKotlinコードをコンパイルしましょう。
$ kotlinc BackingField.kt
これで、javapを使用してバイトコードを検査できます。
$ javap -c -p com.baeldung.backingfield.HttpResponse
Compiled from "BackingField.kt"
public final class com.baeldung.backingfield.HttpResponse {
private int statusCode;
private final java.lang.String body;
private java.util.Map<java.lang.String, java.lang.String> headers;
// truncated
上に示したように、Kotlinは次の3つのプロパティのバッキングフィールドを生成します。
- デフォルトのアクセサーのみを使用しているため、bodyプロパティ
- 同じ理由で[X4X]ヘッダープロパティ
- また、 statusCode プロパティは、フィールド識別子を参照しているためです。
ただし、 hasBody プロパティはこれらの条件のいずれも満たさないため、Kotlinはそのバッキングフィールドを生成しませんでした。 したがって、生成されたバイトコードにはそのようなフィールドの兆候はありません。
4. 結論
この短いチュートリアルでは、Kotlinのプロパティとカスタムアクセサーについて簡単に復習しました。 その後、Kotlinのバッキングフィールドとそのユースケース、およびバイトコード表現について理解しました。
いつものように、すべての例はGitHubでから入手できます。