Должны ли поля быть явно окончательными, чтобы иметь «правильный» неизменный объект? - PullRequest
5 голосов
/ 18 мая 2010

Вы часто читаете об неизменяемых объектах, требующих, чтобы конечные поля были неизменяемыми в Java. Так ли это на самом деле, или достаточно просто не иметь публичной изменчивости и не изменять ее состояние?

Например, если у вас есть неизменяемый объект, построенный по шаблону построителя, вы можете сделать это, заставив строителя назначить отдельные поля при его построении, или заставив строителя самостоятельно удерживать поля и в конечном итоге вернуть неизменный объект, передав значения к его (частному) конструктору.

Наличие полей final имеет очевидное преимущество - предотвращать ошибки реализации (например, разрешать коду сохранять ссылку на построитель и «строить» объект несколько раз, фактически изменяя существующий объект), но при этом Builder сохраняет его данные внутри объекта в том виде, в котором они построены, выглядят как СУШКА.

Таким образом, вопрос заключается в следующем: если предположить, что Builder не утечет Объект рано и не прекратит изменять объект после его создания (скажем, установив ссылку на объект как нулевое), действительно ли что-то получено (например, улучшена безопасность потока) в «неизменности» объекта, если поля объекта были сделаны окончательными вместо этого?

Ответы [ 5 ]

6 голосов
/ 18 мая 2010

Да, вы получаете «потокобезопасность» из полей final. То есть значение, присвоенное полю final во время построения, гарантированно будет видимым для всех потоков. Другой альтернативой для обеспечения безопасности потоков является объявление полей volatile, но с каждым чтением & hellip возникают большие накладные расходы; и сбивает с толку любого, кто смотрит на ваш класс и удивляется, почему поля этого «неизменяемого» класса помечены как «изменчивые».

Маркировка полей final технически наиболее правильная и наиболее четко передает ваши намерения. К сожалению, это делает конструктор очень громоздким. Я думаю, что должна быть возможность создать процессор аннотаций для синтеза компоновщика для неизменяемого класса, так же, как Project Lombok делает с сеттерами и геттерами. Реальная работа заключалась бы в поддержке IDE, необходимой для того, чтобы вы могли писать код против тех, кто на самом деле не существует.

2 голосов
/ 18 мая 2010

Объект, безусловно, может иметь изменяемые приватные поля и все еще работать как неизменяемый объект. Все, что имеет значение для выполнения договора об неизменности, - это то, что объект кажется неизменным извне. Например, объект с неконечными частными полями, но без установщиков, удовлетворяет этому требованию.

Фактически, если ваша инкапсуляция верна, вы можете фактически изменить внутреннее состояние и все еще успешно работать как «неизменный» объект. Примером может служить своего рода ленивая оценка или кэширование структур данных.

Например, Clojure делает это во внутренней реализации ленивых последовательностей, эти объекты ведут себя так, как если бы они были неизменяемыми, но фактически вычисляют и сохраняют будущие значения, когда они запрашиваются напрямую. Любой последующий запрос извлекает сохраненное значение.

Однако - я хотел бы добавить в качестве предостережения, что число мест, где вы на самом деле хотели бы видоизменить внутреннюю часть неизменяемого объекта, вероятно, довольно редко. Если сомневаетесь, сделайте их окончательными.

0 голосов
/ 27 октября 2011

Комментарий: @ Erickson

Вот так:

class X { volatile int i, j; }
X y;

// thread A: 
X x = new X;
x.i = 1;
x.j = 2;
y = x;

// thread B: 
if (y != null) {
    a = y.i; 
    b = y.j;
}

0 голосов
/ 18 мая 2010

Вы определенно можете иметь неизменный объект с неокончательными полями.

Например, см. Java 1.6 реализацию java.lang.String.

0 голосов
/ 18 мая 2010

Я думаю, вам просто нужно рассмотреть среду, в которой она работает, и решить, являются ли фреймворки, использующие отражение для манипулирования объектами, опасными.

Можно легко придумать сценарий странного случая, когда предположительно неизменный объект засоряется с помощью атаки POST-инъекцией из-за структуры веб-привязки, настроенной на использование отражения вместо установщиков бинов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...