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から入手できます。