Есть одна важная вещь для создания настоящих неизменных.Возможно, компоненты являются изменяемыми структурами данных, такими как java.util.Date
.Возьмите этот простой класс для демонстрационных целей:
final class DateWrapper {
private final Date date;
public DateWrapper(Date date) {
this.date = date;
}
public Date getDate() {
return date;
}
}
Теперь вы можете написать этот код:
DateWrapper dw = new DateWrapper(new Date());
dw.getDate().setYear(2020);
Это изменяет переменную экземпляра date
объекта dw
класса DateWrapper
.Так что этот класс не является действительно неизменным.
Чтобы решить эту проблему, вы должны сделать защитные копии, например:
final class DateWrapper {
private final Date date;
public DateWrapper(Date date) {
// It must not be possible to modify the date after construction.
// So use a copy of the original object in class DateWrapper.
this.date = new Date(date.getTime());
}
public Date getDate() {
// It must not be possible to modify the date in DateWarapper
// So return a copy.
return new Date(date.getTime());
}
}
Так что ни один другой класс не получит изменяемую ссылку на внутренние элементы DateWrapper
.
Еще одно правило: сделать ваш класс окончательным, иначе подкласс может вести себя как класс immutabele, нарушая контракт неизменности.Это пример вредоносного подкласса, который работает, только если DateWrapper не является окончательным:
class Date2Wrapper extends DateWrapper {
final Date date2;
public Date2Wrapper(Date date) {
super(date);
this.date2 = date;
}
public Date getDate() {
return date2;
}
}