web-dev-qa-db-ja.com

Kotlinバッキングフィールドとは何ですか?

Java開発者として、バッキングフィールドの概念は私には少し異質です。

   class Sample {
        var counter = 0 // the initializer value is written directly to the backing field
        set(value) {
            if (value >= 0) field = value
        }
    }

このバッキングフィールドは何に適していますか? Kotlin docs 前述:Kotlinのクラスにフィールドを含めることはできません。ただし、カスタムアクセサを使用する場合は、バッキングフィールドが必要になる場合があります。どうして?セッター内でプロパティ名自体を使用することとの違いは何ですか?.

    class Sample {        
        var counter = 0
        set(value) {
            if (value >= 0) this.counter = value // or just counter = value?
        }
    }
69
Yudhistira Arya

なぜなら、fieldキーワードがない場合、get()またはset(value)の値を実際に設定/取得することはできないからです。これにより、カスタムアクセサーのバッキングフィールドにアクセスできます。

これは、同等のJavaサンプルのコード:

class Sample {
    private int counter = 0;
    public void setCounter(int value) {
        if (value >= 0) setCounter(value);
    }
    public int getCounter() {
        return counter;
    }
}

セッターはそれ自体への無限の再帰であり、何も変更しないため、これは良くないようです。 foo.bar = valuePUTFIELDの代わりにセッター呼び出しに変換されます。


編集:Javaにはフィールドがありますが、Kotlinにはプロパティがあり、これはフィールドよりもかなり高いレベルの概念です。

プロパティには2つのタイプがあります。1つはバッキングフィールドがあり、もう1つはありません。

バッキングフィールドを持つプロパティは、値をフィールドの形式で格納します。このフィールドにより、メモリに値を保存できます。そのようなプロパティの例は、firstsecondおよびPairプロパティです。そのプロパティは、Pairのメモリ内表現を変更します。

バッキングフィールドのないプロパティは、メモリに直接保存する以外の方法で値を保存する必要があります。他のプロパティ、またはオブジェクト自体から計算する必要があります。このようなプロパティの例としては、indicesList拡張プロパティがあります。これは、フィールドではなく、sizeプロパティに基づく計算結果です。したがって、Listのメモリ内表現は変更されません(Javaが静的に入力されるため、まったく実行できません)。

66
glee8e

最初は、私もこの概念を理解するのに苦労しました。例を使用して説明します。

このKotlinクラスを検討してください

class DummyClass {
    var size = 0;
    var isEmpty
        get() = size == 0
        set(value) {
            size = size * 2
        }
}

コードを見ると、2つのプロパティ、つまりsize(デフォルトアクセサー付き)とisEmpty(カスタムアクセサー付き)があることがわかります。ただし、フィールドは1つだけです(つまり、size)。フィールドが1つしかないことを理解するために、このクラスに相当するJavaを見てみましょう。

[ツール]-> [Kotlin]-> [Kotlin ByteCode in AndroidStudio。Decompileをクリックします。

   public final class DummyClass {
   private int size;

   public final int getSize() {
      return this.size;
   }

   public final void setSize(int var1) {
      this.size = var1;
   }

   public final boolean isEmpty() {
      return this.size == 0;
   }

   public final void setEmpty(boolean value) {
      this.size *= 2;
   }
}

明らかに、JavaクラスにはisEmptyのゲッター関数とセッター関数のみがあり、そのために宣言されたフィールドはありません。同様に、Kotlinには、バッキングフィールドはありませんプロパティはそのフィールドにまったく依存しないため、プロパティisEmptyです。


isEmptyプロパティのカスタムゲッターとセッターを削除しましょう。

class DummyClass {
    var size = 0;
    var isEmpty = false
}

そして、Java上記のクラスに相当するものは

public final class DummyClass {
   private int size;
   private boolean isEmpty;

   public final int getSize() {
      return this.size;
   }

   public final void setSize(int var1) {
      this.size = var1;
   }

   public final boolean isEmpty() {
      return this.isEmpty;
   }

   public final void setEmpty(boolean var1) {
      this.isEmpty = var1;
   }
}

ここには、フィールドsizeisEmptyの両方があります。 isEmptyプロパティのゲッターとセッターはそれに依存するため、isEmptyはバッキングフィールドです。

10

バッキングフィールドは、検証を実行したり、状態が変化したときにイベントをトリガーしたりするのに適しています。コードをJava setter/getterに追加したときを考えてください。バッキングフィールドは同様のシナリオで役立ちます。セッター/ゲッター。

フィールドにフィールド名自体を割り当てる場合、実際にはセッター(つまりset(value))を呼び出しています。あなたが持っている例では、this.counter = valueは、スタックがオーバーフローするまでset(value)に再帰します。 fieldを使用すると、セッター(またはゲッター)コードがバイパスされます。

9
Mark Mucha

私の理解は、プロパティ値を変更または使用するときにgetまたはsetのプロパティ値への参照としてfield identifierを使用することですgetまたはset

例えば:

class A{
    var a:Int=1
        get(){return field * 2}    // Similiar to Java: public int geta(){return this.a * 2}
        set(value) {field = value + 1}
}

次に:

var t = A()
println(t.a)    // OUTPUT: 2, equal to Java code: println(t.a * 2)
t.a = 2         // The real action is similar to Java code: t.a = t.a +1
println(t.a)    // OUTPUT: 6, equal to Java code: println(t.a * 2)
0
Freddie