JavaRush /Курси /JAVA 25 SELF /Ініціалізація статичних і final-полів

Ініціалізація статичних і final-полів

JAVA 25 SELF
Рівень 15 , Лекція 3
Відкрита

1. Статичні поля: як ініціалізувати?

Статичне поле (static) належить не об’єкту, а всьому класу водночас. Його значення існує в одному примірнику для всіх об’єктів цього класу. Як аналогію можна навести приклад «спільної каси» для всіх співробітників компанії: байдуже, хто саме прийшов, каса одна на всіх.

Ініціалізація під час оголошення

Найпростіший і найпоширеніший спосіб ініціалізації статичного поля — присвоїти йому значення безпосередньо під час оголошення:

public class User {
    private static int userCount = 0; // ініціалізація прямо тут

    // ... інший код
}

Таке поле буде ініціалізовано під час першого завантаження класу User у пам’ять.

Ініціалізація у статичному блоці

Іноді потрібна складніша логіка ініціалізації — наприклад, завантажити дані з файлу або виконати обчислення. У цьому разі використовують статичний блок ініціалізації:

public class Config {
    public static String configPath;

    static {
        // Цей блок виконається ОДИН раз під час завантаження класу
        configPath = System.getenv("APP_CONFIG_PATH");
        if (configPath == null) {
            configPath = "/etc/app/default.conf";
        }
        System.out.println("Шлях до конфігурації ініціалізовано: " + configPath);
    }
}

Коли виконується статичний блок?

  • Під час першого звернення до класу (наприклад, коли створюється перший об’єкт або викликається будь-який статичний метод чи поле).
  • Виконується лише один раз для кожного класу.

Особливості доступу до статичних полів

  • До статичних полів звертаються через ім’я класу: User.userCount.
  • Можна звертатися й через об’єкт, але це вважають поганим стилем (плутає того, хто читає код).

Приклад:

User u1 = new User();
User u2 = new User();
System.out.println(User.userCount); // правильно
System.out.println(u1.userCount);   // працює, але не рекомендується!

2. final-поля: коли й як ініціалізувати?

final — це модифікатор, який означає: «Це поле можна присвоїти лише один раз, а далі його змінити не можна». Після ініціалізації значення поля стає незмінним: для об’єкта — це його фіксована властивість, а для класу (якщо поле статичне) — спільна константа.

Приклади використання:

  • Константи (наприклад, PI).
  • Унікальний ідентифікатор об’єкта, який не можна змінювати після створення.

Вимоги до ініціалізації final-полів

У Java є суворе правило: кожне final-поле обов’язково має бути ініціалізоване або під час оголошення, або в кожному конструкторі класу.

Ініціалізація під час оголошення

public class Circle {
    public static final double PI = 3.1415926535; // константа класу
    private final String id = "CIRCLE";           // константа об’єкта
}

Ініціалізація в конструкторі

Іноді значення final-поля відоме лише під час створення об’єкта:

public class User {
    private final int id;

    public User(int id) {
        this.id = id; // присвоюємо final-поле в конструкторі
    }
}

Важливо: якщо у класі кілька конструкторів, final-поле має бути ініціалізовано у кожному з них!

Комбінований приклад

public class Token {
    private final String value;
    private final long timestamp;

    public Token(String value) {
        this.value = value;
        this.timestamp = System.currentTimeMillis();
    }
}

Помилки компіляції під час неправильної ініціалізації

Якщо ви забудете ініціалізувати final-поле, компілятор не дозволить скомпілювати програму:

public class Broken {
    private final int x; // не ініціалізовано

    public Broken() {
        // x не присвоюється!
    }
}
// Помилка: variable x might not have been initialized

3. Комбінація static і final: оголошення констант класу

Дуже часто використовують комбінацію модифікаторів public static final. У Java так оголошують константи класу — значення, що задаються один раз і не змінюються протягом роботи програми. Ці константи належать усьому класу й однакові для всіх його об’єктів.

Синтаксис і приклад

public class MathUtils {
    public static final double PI = 3.1415926535;
    public static final String APP_NAME = "MyApp";
}

Пояснення:

  • public — видимий звідусіль.
  • static — належить усьому класу, а не окремому об’єкту.
  • final — не можна змінити після ініціалізації.

Використання

double area = MathUtils.PI * r * r;
System.out.println(MathUtils.APP_NAME);

Конвенція: імена констант зазвичай пишуться ВЕЛИКИМИ_ЛІТЕРАМИ_З_ПІДКРЕСЛЕННЯМ.

4. Приклади коду: варіанти ініціалізації статичних і final-полів

Приклад 1: Простий клас із константою

public class Constants {
    public static final int DAYS_IN_WEEK = 7;
    public static final String COMPANY = "ТОВ Ромашка";
}

Приклад 2: Статичне поле, ініціалізоване у статичному блоці

public class AppConfig {
    public static final String DEFAULT_PATH;

    static {
        // Можна виконати складну логіку
        String env = System.getenv("APP_PATH");
        if (env != null) {
            DEFAULT_PATH = env;
        } else {
            DEFAULT_PATH = "/usr/local/app";
        }
    }
}

Приклад 3: final-поле об’єкта, ініціалізація в конструкторі

public class User {
    private static int nextId = 1;
    private final int id;
    private String name;

    public User(String name) {
        this.id = nextId++;
        this.name = name;
    }

    public int getId() { 
        return id; 
    }
    public String getName() {
        return name; 
    }
    public void setName(String name) { 
        this.name = name; 
    }
}

Використання:

User u1 = new User("Іван");
User u2 = new User("Марія");
System.out.println(u1.getId()); // 1
System.out.println(u2.getId()); // 2

Приклад 4: Помилка під час неправильної ініціалізації final-поля

public class BadExample {
    private final int number;

    public BadExample() {
        // number не ініціалізовано!
    }
}
// Помилка компіляції: variable number might not have been initialized

5. Найкращі практики роботи зі статичними та final-полями

Використовуйте public static final лише для справжніх констант

Якщо значення може змінитися в майбутньому (наприклад, список співробітників), не робіть його final! Константи мають бути справді незмінними.

public static final int MAX_USERS = 1000; // добре
public static final String[] USERS = new String[100]; // погано!

Хоча саме посилання USERS не зміниться, вміст масиву можна змінювати. Це може призвести до неочікуваних помилок.

Для складної ініціалізації використовуйте статичні блоки

Якщо константу не можна виразити простим присвоєнням (наприклад, потрібне обчислення або читання з файлу), використовуйте статичний блок.

Не зловживайте статичними полями

Статичні поля — це глобальні змінні. Їх занадто велика кількість може призвести до важковловимих помилок і складної підтримки коду.

Не робіть змінювані об’єкти public static final

Якщо об’єкт змінюваний, не робіть його публічним і фінальним. Це відкриє доступ до його внутрішнього стану для всіх, і хтось обов’язково скористається цим.

6. Типові помилки під час ініціалізації статичних і final-полів

Помилка № 1: Неініціалізоване final-поле. Якщо забути ініціалізувати final-поле або під час оголошення, або в усіх конструкторах, компілятор видасть помилку. Наприклад, якщо у класі два конструктори, а в одному з них ви забули присвоїти значення final-полю — буде помилка.

Помилка № 2: Зміна значення final-поля. Спроба змінити значення final-поля після ініціалізації призведе до помилки компіляції.

public class Demo {
    private final int x = 5;
    public void change() {
        x = 10; // Помилка: cannot assign a value to final variable x
    }
}

Помилка № 3: Публічні змінювані static final‑поля. Якщо зробити змінюваний об’єкт (String[], int[] тощо) public static final, будь-який код зможе змінювати його вміст. Це порушує інкапсуляцію і може призвести до важковловимих помилок.

Помилка № 4: Використання нестатичних полів у статичному блоці. У статичному блоці не можна звертатися до нестатичних полів, оскільки вони ще не ініціалізовані (і взагалі не існують на цьому етапі).

Помилка № 5: Неочікуваний порядок ініціалізації. Якщо у статичному блоці ви звертаєтеся до статичних полів, оголошених нижче в коді, вони можуть ще не бути ініціалізовані. Завжди оголошуйте статичні поля перед статичними блоками, якщо плануєте їх використовувати.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ