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


92

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

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

このバッキングフィールドは何に適していますか?Kotlinのドキュメントによると:

Kotlinのクラスにフィールドを含めることはできません。ただし、カスタムアクセサを使用する場合は、バッキングフィールドが必要になる場合があります

どうして?セッター内でプロパティ名自体を使用することとの違いは何ですか?例:*

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

17
セッターでプロパティ自体を使用すると、プロパティに値を割り当てると常にセッターが呼び出されるため、再帰が無限に発生します。
funglejunk 2017

1
@Strelok my bad .... this.counter = valueKotlinのドキュメントを読んだとき、これはJavaの同等のものと同じだと思っていました。
yudhistira Arya 2017

3
この記事は、フィールドとプロパティを対象としています。
avinash 2018

回答:


86

なぜなら、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;
    }
}

セッターはそれ自体への無限の再帰であり、何も変更しないため、これは明らかに良くありません。kotlinでは、書き込むたびfoo.bar = valueに、ではなくセッター呼び出しに変換されることを忘れないでくださいPUTFIELD


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

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

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

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


答えてくれてありがとう!私の悪い...私はそれthis.counter = valueがJavaの同等物と同じであると思っていました。
Yudhistira Arya 2017

どこに文書化されていますか?ありがとう:)
アルストン

@Alston、ドキュメントは次のとおり
YamashiroRion19年

1
あいまいな説明がたくさん。afieldは、既存のメンバー変数へのポインターまたは参照のようなものであると、単純に言えないのはなぜですか。以来、get/set直ちにfollowescounter従って、fieldキーワードへの参照ですcounter。正しい?
eigenfield

@typelogicこの回答は、C / C ++ではなく、Java / JSのバックグラウンド(当時はKotlin / Nativeはありません)を持つプログラマー向けに最も調整されています。ファジーだと思うのは、他の人にとってはパンとバターです。
glee8e

31

当初、私もこの概念を理解するのに苦労しました。それで、例の助けを借りてそれをあなたに説明させてください。

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

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

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

[ツール]-> [Kotlin]-> [AndroidStudioでKotlinByteCodeを表示]に移動します。逆コンパイルをクリックします。

   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クラスにはのgetter関数とsetter関数しか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それに依存しているため、はバッキングフィールドです。


4
良い説明。ありがとう
SonuSanjeev19年

1
本当に、説明してくれてありがとう。私もJavaからKotlinに来ましたが、プロパティの概念は私にとって新しいものです。しかし、あなたとガイドのおかげで、私はそれを理解しました。:)
山城リオン

神はあなたを祝福するかもしれません。
Andrea Cioccarelli

私はこの答えが好きです、それは正直に事実を引用しています。ので、私は、まだ疑問がよC#はは必要ありませんfieldキーワードが、それはKotlinの言語の改善は、この奇妙削除する可能性がありますfieldキーワードを、無限再帰の奈落の底に落ちるから無力な魂を避けますか?
eigenfield

9

バッキングフィールドは、検証を実行したり、状態の変化時にイベントをトリガーしたりするのに適しています。Javaセッター/ゲッターにコードを追加したときのことを考えてみてください。バッキングフィールドは、同様のシナリオで役立ちます。セッター/ゲッターを制御または可視化する必要がある場合は、バッキングフィールドを使用します。

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


申し訳ありませんが、説明に説明が必要な用語が含まれています。次に、最初にJavaシナリオを引用し、次に突然、警告なしにlainを実際のKotlinステートメントに切り替えました。Kotlinによるキーワードの必要性fieldC#にはないため、ここで引用したものよりも適切な説明が必要です。
eigenfield

2

私の理解では、使用しているフィールドでのプロパティの値を基準として識別子を取得または設定しますが、変更したりして、プロパティの値を使用する場合、GETまたはセット

例えば:

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

用語backing fieldは謎に満ちています。使用されるキーワードはfieldです。get/set方法は、すぐに次のれようとしているメンバ変数に次の取得セットこのドアの保護方法機構を介して。fieldキーワードは、ちょうどされるメンバ変数を参照する設定または取得します。現在、Kotlinでは、getまたはset保護ドアメソッド内で直接メンバー変数を参照することはできません。これは、getまたはsetを再起動するため、残念ながら無限再帰が発生するためです。セットので、深い奈落の底にランタイムダウンをLEDが。

C#しかし、あなたは直接getter / setterメソッドの内部でメンバ変数を参照することができます。この比較を引用して、このfieldキーワードが現在のKotlinの実装方法であるという考えを示していますが、今後のバージョンで削除され、無限再帰を発生させることなくメンバー変数を直接参照できるようになることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.