Ответ
Неизменяемый класс — это класс, состояние которого нельзя изменить после создания. Это ключевая концепция для написания потокобезопасного и предсказуемого кода.
Строгие правила создания immutable-класса:
- Объявите класс как
final— чтобы от него нельзя было наследоваться и переопределить методы. - Все поля объявите как
privateиfinal— инициализация только в конструкторе. - Не предоставляйте сеттеров (setter methods).
- Инициализируйте все поля через конструктор, выполняя глубокое копирование для mutable-аргументов.
- Для getter-методов, возвращающих mutable-объекты, возвращайте защищённые копии или неизменяемые представления.
Пример правильного immutable-класса:
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
public final class ImmutablePerson {
// Примитивы и String уже immutable
private final String name;
private final int age;
// Mutable-объект! Требует особой обработки.
private final List<String> hobbies;
// Конструктор с защитным копированием (defensive copy)
public ImmutablePerson(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
// 1. Создаём копию переданного списка
this.hobbies = new ArrayList<>(hobbies);
// 2. Опционально: делаем список read-only
// this.hobbies = Collections.unmodifiableList(new ArrayList<>(hobbies));
}
// Getter для immutable-полей
public String getName() { return name; }
public int getAge() { return age; }
// Getter для mutable-поля: ВОЗВРАЩАЕМ КОПИЮ или unmodifiable view
public List<String> getHobbies() {
// Возвращаем новую копию, чтобы исходный список нельзя было изменить извне
return new ArrayList<>(hobbies);
// Или возвращаем неизменяемое представление (предпочтительнее для производительности)
// return Collections.unmodifiableList(hobbies);
}
}
Почему это работает:
- Поля
finalгарантируют, что ссылка не изменится после конструктора. - Защитное копирование в конструкторе и геттерах изолирует внутреннее состояние класса от внешнего кода.
- Отсутствие сеттеров исключает прямой способ изменения.
Для ещё большей надёжности используйте библиотеки, такие как AutoValue или Immutables, которые генерируют корректный immutable-код.