← Назад к вопросам

Как достичь иммутабельность класса

1.2 Junior🔥 251 комментариев
#ООП#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Иммутабельность класса в 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. Это хорошие примеры для изучения.