Неизменяемые объекты Java

Сегодня, когда я читал документацию по классу BigDecimal, я наткнулся на фундаментальное свойство класса BigDecimal — Immutable.

Как я мог объяснить своей бабушке концепцию неизменности?

Каковы плюсы и минусы неизменности класса?

Может ли расширенный класс стать изменяемым?

Учитывая, что я хочу расширить BigDecimal своим классом:

`MyBigDecimal extends BigDecimal` 

Нарушает ли расширение основные принципы объектно-ориентированного проектирования?


person Lucian Enache    schedule 17.07.2012    source источник
comment
1. Не меняется. 3. Да, может. 4. Если бы расширение класса нарушило основные принципы ООП, то это не было бы функцией Java.   -  person Marko Topolnik    schedule 17.07.2012
comment
Кстати, BigDecimal, как и многие неизменяемые классы в JDK, являются final, поэтому их нельзя расширять и делать изменяемыми.   -  person Peter Lawrey    schedule 17.07.2012
comment
@PeterLawrey BigDecimal не является окончательным, хотя и должен быть.   -  person assylias    schedule 17.07.2012
comment
@assylias Хороший вопрос. Его методы также не являются окончательными, то есть их можно изменить.   -  person Peter Lawrey    schedule 17.07.2012
comment
@assylias Следовательно, это можно рассматривать как зеленый свет для расширения класса и, в конечном итоге, переопределения его методов?   -  person Lucian Enache    schedule 17.07.2012
comment
@LucianEnache Это не было намерением, но ничто не мешает вам это сделать.   -  person assylias    schedule 17.07.2012


Ответы (4)


Как я мог объяснить своей бабушке концепцию неизменности?

Проверьте этот вопрос: Что подразумевается под неизменным

Или из эффективной Java:

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


Каковы плюсы и минусы неизменности класса?

Плюсы:

  • легче рассуждать о состоянии объекта, потому что есть только одно, состояние, которое было построено при инициализации
  • Следствие: неизменяемые объекты легче использовать в параллельном программировании, где состояние — это все.

Минусы:

  • когда вы хотите изменить свойство объекта, вам нужно создать новый = дорогой
  • конструкция может быть более сложной (см. шаблон строителя)

Может ли расширенный класс стать изменяемым?

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

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

person assylias    schedule 17.07.2012

BigDecimal — это класс значений. Он представляет значение из «реального мира». Возьмем, к примеру, целые числа. 42 всегда имеет значение 42. Его состояние нельзя изменить. Если я хочу иметь 43, это не измененное значение 42, а значение 43. Это абстрактное понятие значений переносится в объектно-ориентированный мир с использованием неизменяемых классов. Если вы хотите добавить число к существующему, оно не изменяется, но создается новый неизменяемый объект, содержащий результат.

person André Stannek    schedule 17.07.2012

Неизменяемый класс, экземпляры которого никогда не меняются. Состояние объекта определяется во время строительства и никогда не меняется после.

Чтобы быть должным образом неизменяемым, класс не предоставляет никакого способа (кроме отражения) для изменения своего состояния: нет метода установки, нет метода, который изменяет его внутреннее состояние, нет метода, который позволяет получить доступ к изменчивому полю, которое он содержит. Он также должен быть окончательным (как и BigDecimal), чтобы предотвратить его расширение любым другим классом и, таким образом, сделать его изменяемым путем добавления изменяемых полей.

Преимуществ много:

  • Класс легко понять
  • Экземпляры по своей сути потокобезопасны
  • Экземпляры могут кэшироваться без необходимости возврата копий из кэша.
  • Экземпляры можно использовать в качестве ключей на Карте, не опасаясь, что они будут изменены после

Это не нарушает принципов ООП: напротив, состояние полностью инкапсулируется в объекте.

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

person JB Nizet    schedule 17.07.2012
comment
Проверьте String.hashCode, он изменяет внутреннее состояние строки, причем совершенно не потокобезопасным способом. - person Marko Topolnik; 17.07.2012
comment
Да, но это противный продвинутый трюк. И это определенно потокобезопасно, так как единственный способ получить доступ к закешированному значению — через метод hashCode(), который пересчитывает его детерминированным образом, если оно равно 0. А присваивания переменных типа int являются атомарными операциями. - person JB Nizet; 17.07.2012
comment
@MarkoTopolnik это потокобезопасно. В худшем случае он вычисляется более одного раза. - person assylias; 17.07.2012
comment
@assylias Да, это потокобезопасно с точки зрения контракта hashCode. Это просто забавный фрагмент кода. Но моя главная мысль заключается в том, что нет никаких требований к методу, который меняет свое внутреннее состояние. - person Marko Topolnik; 17.07.2012
comment
@MarkoTopolnik: согласен. Я добавил примечание к своему ответу, чтобы сделать это более ясным. - person JB Nizet; 17.07.2012

неизменность класса означает, что если объект создан, вы не можете изменить его содержимое.

Рассмотрим, например.

String str = "Hello"; // you can not change content Hello to any other string

Плюсы и минусы immutability of a class - Pros. / Минусы неизменности и изменчивости

Может ли расширенный класс стать изменяемым?

Да, вы можете это сделать.

MyBigDecimal extends BigDecimal

Вы можете сделать это BigDecimal не окончательно.

person Nandkumar Tekale    schedule 17.07.2012
comment
На самом деле, вы можете изменить его содержимое. Строка является примером, если я правильно помню (ленивое кэширование hashCode). Просто внешнее поведение не должно меняться. - person Marko Topolnik; 17.07.2012
comment
@MarkoTopolnik: точно... :) - person Nandkumar Tekale; 17.07.2012
comment
@MarkoTopolnik Ленивое кэширование хэш-кода нормально, если оно не видно извне. Еще одна проблема со строкой заключается в том, что ее можно изменить с помощью конструктора CharSequence. В качестве примера см. этот вопрос. - person assylias; 17.07.2012
comment
@assylias Конечно, все в порядке, могу ли я сомневаться в неизменности String? :) - person Marko Topolnik; 17.07.2012