Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Иммутабельность класса в Java
Иммутабельный (неизменяемый) класс — это класс, объекты которого не могут быть изменены после создания. Это фундаментальный принцип безопасного программирования, особенно в многопоточных приложениях.
Правила создания иммутабельного класса
1. Класс должен быть final:
Предотвращает создание подклассов, которые могли бы переопределить методы и нарушить иммутабельность.
public final class Person {
// ...
}
2. Все поля должны быть private и final:
private final String name;
private final int age;
private final LocalDate birthDate;
3. Инициализация только в конструкторе:
Нельзя использовать сеттеры или изменять поля после создания объекта.
public Person(String name, int age, LocalDate birthDate) {
this.name = name;
this.age = age;
this.birthDate = birthDate;
}
4. Глубокое копирование при работе с изменяемыми объектами:
Если у класса есть ссылочные типы данных (List, Date и т.д.), нужно копировать их, чтобы предотвратить внешние изменения.
public final class User {
private final String username;
private final List<String> roles;
public User(String username, List<String> roles) {
this.username = username;
// Создаём копию списка, чтобы избежать изменений извне
this.roles = new ArrayList<>(roles);
}
public List<String> getRoles() {
// Возвращаем неизменяемую копию
return Collections.unmodifiableList(roles);
}
}
Полный пример
public final class BankAccount {
private final String accountNumber;
private final String owner;
private final BigDecimal balance;
private final LocalDateTime createdAt;
public BankAccount(
String accountNumber,
String owner,
BigDecimal balance,
LocalDateTime createdAt
) {
this.accountNumber = accountNumber;
this.owner = owner;
// Копируем BigDecimal, так как это может быть изменено
this.balance = new BigDecimal(balance.toPlainString());
this.createdAt = createdAt;
}
public String getAccountNumber() {
return accountNumber;
}
public String getOwner() {
return owner;
}
public BigDecimal getBalance() {
return new BigDecimal(balance.toPlainString());
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
// Вместо setBalance используем метод, возвращающий новый объект
public BankAccount withBalance(BigDecimal newBalance) {
return new BankAccount(accountNumber, owner, newBalance, createdAt);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BankAccount)) return false;
BankAccount that = (BankAccount) o;
return Objects.equals(accountNumber, that.accountNumber) &&
Objects.equals(owner, that.owner) &&
Objects.equals(balance, that.balance);
}
@Override
public int hashCode() {
return Objects.hash(accountNumber, owner, balance);
}
}
Преимущества иммутабельности
- Безопасность в многопоточности: Не требуют синхронизации
- Простота отладки: Состояние не меняется неожиданно
- Кэширование: Можно кэшировать и переиспользовать объекты
- Хеширование: Безопасно использовать как ключи в HashMap
- Правильность: Меньше багов благодаря предсказуемому поведению
Примеры встроенных иммутабельных классов
Java стандартная библиотека содержит много иммутабельных классов: String, Integer, LocalDate, BigDecimal. Это хорошие примеры для изучения.