Ответ
Преимущества:
- Потокобезопасность без синхронизации: Поскольку состояние объекта фиксировано после создания, его можно свободно передавать между потоками. Это устраняет целый класс ошибок, связанных с состоянием гонки (race condition).
- Простота и надежность: Отсутствие побочных эффектов делает код предсказуемым, упрощает отладку и рассуждения. Объект не может быть случайно изменен в другом месте программы.
- Безопасное кэширование: Можно кэшировать и свободно повторно использовать экземпляры. Классический пример — пулы строк или перечисления (
enum). Хэш-код можно вычислить один раз при создании и сохранить. - Идеальные ключи для коллекций: Неизменяемость гарантирует, что
hashCode()ключа вHashMapилиHashSetостанется постоянным, что является критическим требованием для корректной работы этих коллекций.
Недостатки:
- Потребление памяти: Каждое "изменение" (например, добавление символа к строке) приводит к созданию нового объекта. В сценариях с интенсивной модификацией это создает нагрузку на сборщик мусора.
- Сложность создания сложных объектов: Для пошагового конструирования объекта со многими полями требуется использовать паттерн Builder или создавать множество промежуточных объектов.
Пример и практика создания на Java:
// 1. Класс объявлен как final, чтобы запретить наследование и переопределение методов.
public final class ImmutablePerson {
// 2. Все поля объявлены как private и final.
private final String name;
private final int age;
private final List<String> hobbies; // Изменяемый объект внутри!
// 3. Данные устанавливаются только в конструкторе.
public ImmutablePerson(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
// 4. КРИТИЧНО: Защитная копия (defensive copy) для изменяемых компонентов.
this.hobbies = new ArrayList<>(hobbies);
}
// 5. Только геттеры, сеттеров нет.
public String getName() { return name; }
public int getAge() { return age; }
// 6. Геттер для изменяемого поля также возвращает защитную копию.
public List<String> getHobbies() {
return new ArrayList<>(hobbies);
}
}
// Использование Builder для удобного создания:
ImmutablePerson person = new ImmutablePerson.Builder()
.setName("Alice")
.setAge(30)
.addHobby("Reading")
.addHobby("Cycling")
.build();