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

Что становится неизменяемым при использовании final: класс или экземпляр класса

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

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

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

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

# Что становится неизменяемым при использовании final: класс или экземпляр

Ответ: Зависит от контекста использования final. Это слово имеет разные значения в зависимости от того, где оно применяется.

1. Final для класса - неизменяемость класса

Когда final применяется к классу, неизменяемым становится сам класс (его структура), а не экземпляры:

final class User {
    private String name;
    
    public User(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
}

// ❌ Нельзя наследовать final класс
class Admin extends User {  // ОШИБКА КОМПИЛЯЦИИ
    // ...
}

// ✅ Можно создавать экземпляры
User user1 = new User("John");
User user2 = new User("Jane");
// user1 и user2 - разные объекты, разные состояния

Что значит final для класса:

  • Класс не может быть наследован (его нельзя расширять)
  • Экземпляры могут быть изменяемы (внутреннее состояние может меняться)
  • Пример: String в Java - final класс, но конкретные String объекты неизменяемы благодаря внутренней реализации

2. Final для переменной - неизменяемость ссылки

Когда final применяется к переменной, неизменяемой становится сама переменная (её ссылка):

final User user = new User("John");

// ❌ Нельзя переприсвоить переменную
user = new User("Jane");  // ОШИБКА КОМПИЛЯЦИИ

// ✅ Но можно менять состояние объекта
// (если класс не имеет других защит)

Что значит final для переменной:

  • Переменная не может быть переприсвоена
  • Сам объект может быть изменяемым
  • Ссылка остаётся указывающей на один и тот же объект

3. Final для поля класса

public class User {
    private final String id;  // неизменяемое поле
    private String name;      // изменяемое поле
    
    public User(String id, String name) {
        this.id = id;      // инициализируется один раз
        this.name = name;
    }
    
    // ❌ Нельзя менять id
    public void setId(String id) {
        this.id = id;  // ОШИБКА КОМПИЛЯЦИИ
    }
    
    // ✅ Можно менять name
    public void setName(String name) {
        this.name = name;
    }
}

4. Final для метода - неизменяемость реализации

Когда final применяется к методу, метод не может быть переопределён в подклассах:

class Parent {
    public final void criticalOperation() {
        System.out.println("Это не должно переопределяться");
    }
}

class Child extends Parent {
    // ❌ Нельзя переопределить final метод
    @Override
    public void criticalOperation() {  // ОШИБКА КОМПИЛЯЦИИ
        System.out.println("...");
    }
}

Практический пример: создание по-настоящему неизменяемого класса

Чтобы класс и его экземпляры были неизменяемыми, нужно комбинировать final:

// ✅ Полностью неизменяемый класс
public final class ImmutableUser {
    private final String id;
    private final String name;
    private final int age;
    
    public ImmutableUser(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    
    public String getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    // Нет setters!
    // Все поля final
    // Сам класс final
}

Сравнение таблица

ПрименениеЧто становится неизменяемымПример
final classСтруктура класса (не может быть наследован)final class String
final variableСсылка переменной (не может быть переприсвоена)final User user = ...
final fieldЗначение поля (инициализируется один раз)private final String id
final methodРеализация метода (не может быть переопределена)public final void method()

Важные различия

1. Final не означает thread-safe

final class User {
    private List<String> phones = new ArrayList<>();  // это изменяемый список!
    
    public void addPhone(String phone) {
        phones.add(phone);  // можно менять содержимое!
    }
}

2. Глубокая неизменяемость сложна

// Чтобы быть полностью неизменяемым:
public final class User {
    private final List<String> phones;  // final ссылка
    
    public User(List<String> phones) {
        // Копируем, чтобы внешний код не мог менять
        this.phones = Collections.unmodifiableList(
            new ArrayList<>(phones)
        );
    }
    
    public List<String> getPhones() {
        return phones;  // читай только!
    }
}

Заключение

При использовании final на класс - неизменяемым становится сам класс (его структура, не его экземпляры).

При использовании final на переменную/поле - неизменяемой становится сама переменная (её ссылка, не объект).

Для создания полностью неизменяемых объектов нужна комбинация: final класс + final поля + нет setters + защита мутируемых полей.

Что становится неизменяемым при использовании final: класс или экземпляр класса | PrepBro