Для чего нужно поле поддержки Котлина?

как разработчик 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 сказал: классы в Котлине не могут иметь полей. Однако иногда при использовании пользовательских аксессоров. Почему? В чем разница с использованием самого имени свойств внутри сеттера, например.

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

3 ответов


, потому что, скажем, если у вас нет 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 = value он будет переведен в сеттер вызов вместо PUTFIELD.


EDIT: Java имеет поля в то время как Котлин свойства, что является концепцией более высокого уровня, чем поля.

существует два типа свойств: один с резервным полем, другой без.

свойство с резервным полем будет хранить значение в виде поля. Это поле делает возможным сохранение значения в памяти. Примером такого свойства является first и second свойства Pair. Это свойство изменит представление в памяти Pair.

свойство без резервного поля должно будет хранить свое значение другими способами, чем непосредственно хранить его в памяти. Он должен быть вычислен из других свойств или самого объекта. Примером такого свойства является indices свойство продления List, который не поддерживается полем, но вычисленный результат, основанный на size собственность. Так что это не изменит память представление List (что он не может сделать вообще, потому что Java статически типизирован).


резервные поля хороши для запуска проверки или запуска событий при изменении состояния. Подумайте о времени, когда вы добавили код в Java setter / getter. Резервные поля были бы полезны в аналогичных сценариях. Вы бы использовали резервные поля, когда вам нужно контролировать или иметь видимость над сеттерами / геттерами.

при назначении поля с самим именем Поля вы фактически вызываете сеттер (т. е. set(value)). В пример вы, this.counter = value будет рекурсировать в set (value) пока мы не переполняем наш стек. Используя field обходит код сеттера (или геттера).


первоначально мне тоже было трудно понять эту концепцию. Поэтому позвольте мне объяснить вам это на примере.

рассмотрим этот класс Котлина

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

теперь, когда мы смотрим на код, мы видим, что он имеет 2 свойства i.e -size (С аксессорами по умолчанию) и isEmpty(пользовательские средства доступа). Но он имеет только 1 поле, т. е. size. Чтобы понять, что он имеет только 1 поле, давайте посмотрим Java-эквивалент этого класса.

перейти к Инструменты - > Котлин - > показать Котлин байт-код в Android Studio. Нажмите на декомпиляцию.

   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, и нет поля, объявленного для него. Аналогично, в Котлине нет поля поддержки для property 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;
   }
}

здесь мы видим, как поля size и isEmpty. isEmpty является резервным полем, потому что геттер и сеттер для isEmpty свойство зависит от него.