Константы (final)
final перед переменной значит «присвоить можно только один раз». После этого — переприсвоить нельзя, компилятор не даст:
final int MAX_USERS = 100;
MAX_USERS = 200; // ❌ ошибка компиляции — final нельзя менять
Константы по конвенции называют ЗАГЛАВНЫМИ_БУКВАМИ_С_ПОДЧЁРКИВАНИЯМИ — так с первого взгляда видно: это значение зафиксировано и не должно меняться по ходу программы.
Копнуть глубже
final на объекте — это ловушка для новичков. final фиксирует ссылку, а не содержимое объекта:
final List<String> names = new ArrayList<>();
names.add("Артур"); // ✅ можно — содержимое объекта меняется
names = new ArrayList<>(); // ❌ нельзя — нельзя поменять саму ссылку
Сама переменная names навсегда указывает на один и тот же список. Но что происходит внутри этого списка — final не запрещает.
static final — это уже настоящая константа класса, одна на все объекты:
class Config {
static final int MAX_USERS = 100; // одна на весь класс
}
Под капотом
Blank final. Поле можно объявить final без значения сразу — но тогда обязан присвоить его ровно один раз в каждом конструкторе:
class User {
final String id;
User(String id) {
this.id = id; // присваивается один раз здесь
}
}
final ≠ неизменяемость (immutable). Это разные вещи: final запрещает менять ссылку, а неизменяемость — это когда сам объект не даёт менять своё содержимое (как String). Объект может быть final-полем и при этом оставаться изменяемым (как ArrayList в примере выше) — и наоборот, можно создавать неизменяемые объекты без final.
• почему `final`-список можно менять изнутри, но не переприсвоить (если дошёл до 2-го слоя).