web-dev-qa-db-fra.com

Qu'est-ce que Kotlin Backing Field?

En tant que développeur Java), le concept de champ de support m’est un peu étranger.

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

A quoi sert ce support? La documentation Kotlin dit: Les classes dans Kotlin ne peuvent pas avoir de champs. Cependant, il est parfois nécessaire d'avoir un champ de sauvegarde lorsque vous utilisez des accesseurs personnalisés . Pourquoi? Quelle est la différence avec l'utilisation des propriétés se nommer à l'intérieur du setter, par exemple.

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

Parce que, par exemple, si vous n'avez pas le mot clé field, vous ne pourrez pas définir/obtenir la valeur dans la fonction get() ou set(value). Il vous permet d'accéder au champ de sauvegarde dans les accesseurs personnalisés.

C’est l’équivalent Java de votre exemple:

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

Apparemment, ce n’est pas bon, le poseur n’est qu’une récursion infinie en elle-même, ne changeant jamais rien. Rappelez-vous dans kotlin chaque fois que vous écrivez foo.bar = value il sera traduit en un appeleur au lieu de PUTFIELD.


EDIT: Java a champs alors que Kotlin a propriétés, ce qui est un concept de niveau plutôt supérieur à celui des champs.

Il existe deux types de propriétés: une avec un champ de sauvegarde, une sans.

Une propriété avec un champ de sauvegarde stockera la valeur sous la forme d'un champ. Ce champ permet de stocker une valeur en mémoire. Un exemple d'une telle propriété est les propriétés first et second de Pair. Cette propriété modifiera la représentation en mémoire de Pair.

Une propriété sans champ de sauvegarde devra stocker sa valeur autrement que directement en mémoire. Il doit être calculé à partir d'autres propriétés, ou de l'objet lui-même. Un exemple d'une telle propriété est la propriété d'extension indices de List, qui n'est pas sauvegardée par un champ, mais par un résultat calculé basé sur la propriété size. Donc, cela ne changera pas la représentation en mémoire de List (ce qui ne peut pas du tout se produire car Java est typé de manière statique).

66
glee8e

Au départ, moi aussi j'ai eu du mal à comprendre ce concept. Alors laissez-moi vous expliquer avec l'aide d'un exemple.

Considérez cette classe de Kotlin

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

Maintenant, quand on regarde le code, on peut voir qu’il a 2 propriétés, i.e - size (avec les accesseurs par défaut) et isEmpty (avec les accesseurs personnalisés). Mais il n’a qu’un seul champ, c’est-à-dire size. Pour comprendre qu’il ne possède qu’un seul champ, voyons l’équivalent Java de cette classe).

Allez dans Outils -> Kotlin -> Afficher le ByteCode Kotlin dans Android Studio. Cliquez sur Décompiler.

   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;
   }
}

Nous pouvons clairement voir que la classe Java n'a que des fonctions getter et setter pour isEmpty, et qu'il n'y a pas de champ déclaré pour cela. De même, dans Kotlin, il n'y a pas de champ de sauvegarde pour property isEmpty, car la propriété ne dépend pas du tout de ce champ, donc pas de champ de sauvegarde.


Supposons maintenant le getter et le configurateur personnalisés de la propriété isEmpty.

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

Et l’équivalent Java de la classe ci-dessus est

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;
   }
}

Nous voyons ici les champs size et isEmpty. isEmpty est un champ de support car le getter et le configurateur de la propriété isEmpty en dépendent.

10
thedarkpassenger

Les champs de sauvegarde sont utiles pour exécuter la validation ou déclencher des événements lors du changement d'état. Pensez aux moments où vous avez ajouté du code à un Java setter/getter. Les champs de sauvegarde seraient utiles dans des scénarios similaires. Vous utiliseriez des champs de sauvegarde lorsque vous deviez contrôler ou avoir une visibilité sur les setters/Getters.

Lorsque vous assignez le champ avec le nom de champ lui-même, vous appelez en réalité le séparateur (c'est-à-dire set(value)). Dans l'exemple que vous avez, this.counter = value _ recurse dans set (valeur) jusqu'à ce que nous débordions notre pile. Utiliser field contourne le code de définition (ou getter).

9
Mark Mucha

D'après ce que je comprends, on utilise champ identificateur comme référence à la valeur de la propriété dans get ou set, lorsque vous souhaitez modifier ou utiliser la valeur de la propriété dans get ou set.

Par exemple:

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}
}

Ensuite:

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