Значение "поверхностно неизменяемый" в документации Запись в Java 14 - PullRequest
22 голосов
/ 28 мая 2020

Я читаю документацию Records и не понимаю термина «поверхностно неизменяемый». Что мы подразумеваем под поверхностно неизменяемым ? А если он неизменен, зачем нам конструктор копирования? Почему два «Hello Worlds!»?

Для всех классов записей должен соблюдаться следующий инвариант: если компоненты записи R c1, c2, ... cn, то, если экземпляр записи копируется следующим образом:

 R copy = new R(r.c1(), r.c2(), ..., r.cn());  // copy constructor ?

тогда должно быть так r.equals(copy).

Ответы [ 2 ]

24 голосов
/ 28 мая 2020

Полностью неизменяемый означает, что если у класса есть поля, эти поля обрабатываются как final. Однако их поля (т.е. поля полей) не обязательно должны быть final.

Вам не нужно реализовывать конструктор, он уже реализован таким образом для вас. Но если вы решите реализовать его самостоятельно, например, для проверки аргумента, этот инвариант должен сохраниться.

10 голосов
/ 28 мая 2020

Если вы рассматриваете класс как составную часть или иерархию других классов и примитивов (целые числа, массивы и т. Д. c.), Неглубокая неизменяемость относится к неизменяемости (неизменности) только первого уровня.

Это контрастирует с термином «глубокая неизменность», который относится к неизменности всей иерархии. Большинство ощутимых преимуществ, которые вы слышите о неизменности, таких как неявная потокобезопасность, применимы только к чему-то глубоко неизменяемому.

Рассмотрим этот класс . Его нельзя изменить напрямую, но можно изменить косвенно, например

foo.getBar().setSomeProperty(5);

, поэтому он не является полностью неизменяемым.

Другой пример неглубокой неизменяемости, использующей только примитивы

class Foo {
    private final int[] ints;

    Foo(int[] ints) {
        this.ints = ints;
    }
}

Это может быть изменено следующим образом

int[] ints = {1};
Foo foo = new Foo(ints);
ints[0] = 2;

Для небольшой иерархии иногда просто сделать неглубоко неизменяемый класс глубоко неизменяемый. Обычно это включает в себя защитные копии или переключение изменяемых классов на неизменяемые варианты.

class Foo {
    private final int[] ints; 

    Foo(int[] ints) {
        // copy to protect against the kind of mutation shown above
        this.ints = Arrays.copyOf(ints, ints.length);
    }

    // if you must have a getter for an array, make sure not to return the array itself, 
    // otherwise the caller can change it.
    // for performance reasons, consider an immutable List instead - no copy required
    int[] getInts() {
        return Arrays.copyOf(ints, ints.length);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...