Static и final

Базовый Java
≈ 3 мин чтения

Обычно поле или метод принадлежит конкретному объекту. Но иногда значение должно быть общим для всего класса, а иногда — наоборот, его нужно запретить заменять после инициализации. Для этих двух задач в Java используются ключевые слова static и final.

static — один член на весь класс

Член с модификатором static принадлежит классу, а не отдельному объекту. Поэтому все экземпляры работают с одним и тем же статическим полем.

class User {
    static int count;
    String name;

    User(String name) {
        this.name = name;
        count++;
    }
}

User first = new User("Alice");
User second = new User("Bob");

System.out.println(User.count); // 2

У first и second разные поля name, но поле count общее. Обращаться к статическим членам принято через имя класса: User.count.

Статическими могут быть и методы. Такой метод можно вызвать без создания объекта, если для его работы не нужно состояние конкретного экземпляра.

class MathUtils {
    static int square(int value) {
        return value * value;
    }
}

int result = MathUtils.square(5);

Статический метод не связан с конкретным объектом, поэтому внутри него нельзя напрямую использовать нестатические поля и методы или ключевое слово this. Для доступа к состоянию экземпляра сначала нужен сам экземпляр.

final — назначить один раз

Для переменной final означает, что после присваивания ей нельзя назначить другое значение.

final int maxAttempts = 3;

// maxAttempts = 4; // compile-time error

То же правило работает для полей. final-поле можно инициализировать сразу или присвоить ему значение в конструкторе. После этого заменить значение уже нельзя.

class Order {
    final int id;

    Order(int id) {
        this.id = id;
    }
}
final-ссылка не делает объект неизменяемым. Нельзя переназначить саму ссылку, но состояние объекта всё ещё может изменяться, если его класс это позволяет.
final User user = new User("Alice");

user.name = "Bob";              // OK
// user = new User("Carol");    // compile-time error

final у методов и классов

Модификатор final можно применять не только к переменным. final-метод нельзя переопределить в подклассе, а от final-класса нельзя наследоваться.

class BaseService {
    final void printVersion() {
        System.out.println("1.0");
    }
}

final class AppConfig {
}

Это используют, когда поведение метода или сам класс не должны изменяться через наследование. Сам по себе final не делает остальные поля объекта неизменяемыми.

static final — константы класса

Если значение должно быть одновременно общим для класса и назначаться только один раз, модификаторы объединяют: static final. Так обычно объявляют константы класса.

class Limits {
    static final int MAX_ATTEMPTS = 3;
}

System.out.println(Limits.MAX_ATTEMPTS);

Для таких констант в Java принято использовать имена в верхнем регистре с подчёркиваниями. Важно различать роли модификаторов: static делает член общим для класса, а final запрещает присвоить ему новое значение после инициализации.