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

Что такое Final?

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

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

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

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

Final в Java

Final — это модификатор в Java, который запрещает изменение (overriding, reassignment или extension) элемента. Применяется к классам, методам и переменным с разными эффектами.

1. Final для классов (предотвращает наследование)

Final класс нельзя наследовать (extend):

// Класс помечен как final
public final class ImmutableString {
    private final String value;
    
    public ImmutableString(String value) {
        this.value = value;
    }
    
    public String getValue() {
        return value;
    }
}

// ❌ Ошибка компиляции: Cannot extend final class
public class MyString extends ImmutableString {
    // ...
}

Примеры из Java SDK:

  • java.lang.String — final класс
  • java.lang.Integer — final класс
  • java.lang.Exception — final класс

Зачем делать класс final?

  • Безопасность: предотвратить опасное переопределение
  • Производительность: компилятор может оптимизировать вызовы
  • Неизменяемость (immutability)

2. Final для методов (предотвращает переопределение)

Final метод нельзя переопределить (override) в подклассе:

public class Parent {
    // Обычный метод — может быть переопределён
    public void normalMethod() {
        System.out.println("Parent.normalMethod");
    }
    
    // Final метод — нельзя переопределить
    public final void criticalMethod() {
        System.out.println("Parent.criticalMethod");
    }
}

public class Child extends Parent {
    @Override
    public void normalMethod() {
        System.out.println("Child.normalMethod"); // ✓ OK
    }
    
    @Override
    public final void criticalMethod() { // ❌ Ошибка компиляции!
        System.out.println("Child.criticalMethod");
    }
}

Примеры из Java SDK:

public class Object {
    // Эти методы final и нельзя переопределить
    public final void wait() throws InterruptedException { ... }
    public final void notify() { ... }
    public final void notifyAll() { ... }
}

Зачем делать метод final?

  • Гарантировать определённое поведение
  • Безопасность синхронизации (например, synchronized методы)
  • Производительность: JVM может встроить метод (inline)

3. Final для переменных (предотвращает переизменение)

Final переменная может быть инициализирована только один раз:

public class Configuration {
    // Глобальная константа (инициализация в момент объявления)
    public static final double PI = 3.14159265359;
    
    // Объектная переменная (инициализация в конструкторе)
    private final String databaseUrl;
    private final int maxConnections;
    
    public Configuration(String dbUrl, int maxConns) {
        // ✓ Первая и только одна инициализация
        this.databaseUrl = dbUrl;
        this.maxConnections = maxConns;
    }
    
    public void tryToModify() {
        // ❌ Ошибка компиляции: Cannot assign a value to final variable
        // databaseUrl = "new-url";
        // maxConnections = 100;
    }
}

Разница: Final для примитивов vs объектов

Важно понимать: final для объекта запрещает смену ссылки, а не содержимого:

public class FinalReferences {
    public static void main(String[] args) {
        // Final примитив: значение нельзя менять
        final int age = 25;
        // age = 30; // ❌ Ошибка
        
        // Final объект: ссылку нельзя менять, но содержимое можно
        final List<String> names = new ArrayList<>();
        
        // ✓ OK: модифицируем содержимое
        names.add("Alice");
        names.add("Bob");
        names.remove(0);
        System.out.println(names); // [Bob]
        
        // ❌ Ошибка: менять ссылку нельзя
        // names = new ArrayList<>();
    }
}

Для истинной неизменяемости нужны другие подходы:

public class ImmutableList {
    public static void main(String[] args) {
        // Истинно неизменяемый список
        final List<String> immutable = Collections.unmodifiableList(
            new ArrayList<>(Arrays.asList("A", "B"))
        );
        
        // ✓ Чтение работает
        System.out.println(immutable.get(0)); // A
        
        // ❌ Модификация выбросит исключение
        // immutable.add("C"); // UnsupportedOperationException
    }
}

4. Final для переменных метода (Local Final Variables)

public class LocalFinalVariables {
    public void printMessage() {
        // Local final переменная
        final String message = "Hello, World!";
        // message = "Changed"; // ❌ Ошибка
        System.out.println(message);
    }
    
    public void anonymousClassExample() {
        final int outerVariable = 10; // Должна быть final
        
        // Анонимный класс может использовать final переменные
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(outerVariable); // ✓ Может использовать
            }
        };
        
        r.run(); // 10
    }
}

5. Final и многопоточность (Memory Visibility)

Final переменные гарантируют видимость в многопоточной среде:

public class ThreadSafeFinal {
    private final String data; // Гарантирует видимость
    private String notFinal;   // Может быть не видна другим потокам
    
    public ThreadSafeFinal(String data, String notFinal) {
        this.data = data;           // Happens-before для других потоков
        this.notFinal = notFinal;   // Может быть data race!
    }
    
    public void readData() {
        System.out.println(data);       // ✓ Безопасно видит значение
        System.out.println(notFinal);   // ⚠️ Может быть data race
    }
}

Final гарантирует, что значение, установленное в конструкторе, будет видно всем потокам.

6. Final в методах с параметрами

public class FinalParameters {
    // Final параметры метода
    public void process(final String input, final int value) {
        System.out.println(input + value);
        
        // ❌ Ошибка: нельзя переиграть final параметры
        // input = "changed";
        // value = 999;
    }
}

Когда использовать final параметры?

  • Редко, в основном стиль предпочтения
  • Может улучшить читаемость кода
  • Помогает IDE дать лучшие подсказки

7. Final и производительность

Final позволяет компилятору и JVM применить оптимизации:

public class FinalOptimization {
    // Final поле: JVM может встроить значение
    private static final int MAX_SIZE = 1000;
    
    public int getMaxSize() {
        return MAX_SIZE; // JVM может заменить на прямое значение 1000
    }
    
    // Final метод: может быть встроен (inlined)
    public final int add(int a, int b) {
        return a + b; // JVM может встроить этот вызов
    }
}

// Результат после JVM оптимизации:
// int getMaxSize() -> return 1000;        (no method call)
// int add(1, 2)   -> return 1 + 2;        (no method call)

Практический пример: Неизменяемый класс (Immutable Class)

public final class Person { // Final класс!
    private final String name;           // Final поле
    private final int age;              // Final поле
    private final List<String> emails;  // Final ссылка
    
    public Person(String name, int age, List<String> emails) {
        this.name = name;
        this.age = age;
        // Оборачиваем список в неизменяемый
        this.emails = Collections.unmodifiableList(
            new ArrayList<>(emails)
        );
    }
    
    public String getName() {
        return name; // Нельзя изменить
    }
    
    public int getAge() {
        return age; // Нельзя изменить
    }
    
    public List<String> getEmails() {
        return emails; // Вернёт неизменяемый список
    }
    
    @Override
    public final int hashCode() {
        return Objects.hash(name, age, emails);
    }
    
    @Override
    public final boolean equals(Object obj) {
        if (!(obj instanceof Person)) return false;
        Person other = (Person) obj;
        return Objects.equals(name, other.name) &&
               age == other.age &&
               Objects.equals(emails, other.emails);
    }
}

Best Practices

  1. Классы: помечай final, если нет причины быть наследуемым
  2. Методы: используй final для критичных методов
  3. Поля: помечай поля final, если они не меняются
  4. Параметры: опционально, зависит от стиля кода
  5. Константы: всегда используй static final
  6. Объекты: помни, что final не означает неизменяемость

Final vs Abstract

// ❌ Логическая ошибка: класс не может быть одновременно
// abstract (должен быть наследован) и final (не может быть наследован)
public abstract final class Contradiction {} // Ошибка компиляции!

// ✓ Правильно: abstract требует наследования
public abstract class AbstractBase {
    public abstract void doSomething();
}

// ✓ Правильно: final запрещает дальнейшее наследование
public final class Concrete extends AbstractBase {
    @Override
    public void doSomething() {
        System.out.println("Done");
    }
}

Final — это мощный инструмент для контроля архитектуры кода, обеспечения безопасности и производительности.

Что такое Final? | PrepBro