À quoi sert Kotlin Backing Field?

En tant que développeur Java, le concept d'un champ de sauvegarde m'est un peu étranger. Donné:

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

À quoi sert ce champ de soutien? Kotlin docs dit: Les Classes dans Kotlin ne peuvent pas avoir de champs. Cependant, il est parfois nécessaire d'avoir un champ de sauvegarde lors de l'utilisation d'accesseurs personnalisés. Pourquoi? Quelle est la différence avec l'utilisation du nom des propriétés lui-même dans le setter, par exemple.

    class Sample {        
        var counter = 0
        set(value) {
            if (value >= 0) this.counter = value // or just counter = value?
        }
    }
55
demandé sur Zumry Mohamed 2017-04-05 04:02:17

3 réponses

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

C'est le code Java équivalent 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, car le setter n'est qu'une récursivité infinie en lui-même, ne changeant jamais rien. Rappelez-vous dans kotlin chaque fois que vous écrivez foo.bar = value il sera traduit en un appel setter au lieu d'un PUTFIELD.


EDIT: Java a fields tandis que Kotlin a properties, ce qui est un concept de niveau plutôt supérieur à fields.

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 de la valeur en mémoire. Un exemple de cette propriété est le first et second propriétés de Pair. Cette propriété va changer la mémoire représentation de Pair.

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

54
répondu glee8e 2018-05-25 07:19:02

Les champs de sauvegarde sont bons pour exécuter la validation ou déclencher des événements lors d'un changement d'état. Pensez aux fois où vous avez ajouté du code à un setter/getter Java. 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 attribuez le champ avec le nom du champ lui-même, vous appelez réellement le setter (c'est-à-dire set(value)). Dans l'exemple que vous avez, this.counter = value serait récursif en set (value) jusqu'à ce que nous débordions notre stack. L'utilisation de field contourne le code setter (ou getter).

8
répondu Mark Mucha 2017-04-05 01:30:11

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

Considérez cette classe Kotlin

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

Maintenant, quand nous regardons le code, nous pouvons voir qu'il a 2 propriétés à savoir - size (avec des accesseurs par défaut) et isEmpty(avec des accesseurs personnalisés). Mais il n'a que 1 Champ, c'est-à-dire size. Pour comprendre qu'il n'a que 1 Champ, voyons L'équivalent Java de cette classe.

Allez dans Outils - > Kotlin - > afficher Kotlin ByteCode 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;
   }
}

Clairement, nous pouvons voir que la classe java n'a que des fonctions getter et setter pour isEmpty, et 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 la propriété isEmpty, puisque la propriété ne dépend pas du tout de ce champ. Donc pas de champ de stockage.


Maintenant, supprimons le getter et le setter 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;
   }
}

Ici, nous voyons à la fois les champs size et isEmpty. isEmpty est un champ de sauvegarde car le getter et le setter de la propriété isEmpty en dépendent.

4
répondu thedarkpassenger 2018-01-16 06:22:54