Коли відбувається ініціалізація статичного класу?


110

Коли ініціалізуються статичні поля? Якщо я ніколи не інстанціюю клас, але я отримую доступ до статичного поля, чи ВСІ статичні блоки та приватні статичні методи, що використовуються для інстанціювання приватних статичних полів, називаються (в порядку) в цей момент?

Що робити, якщо я викликаю статичний метод? Чи він також запускає всі статичні блоки? Перед методом?


Аналогічно для статичних блоків ініціалізаторів: stackoverflow.com/questions/2007666 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Відповіді:


156

Статична ініціалізація класу зазвичай відбувається безпосередньо перед тим, як відбудеться одна з наступних подій:

  • створюється екземпляр класу,
  • викликається статичний метод класу,
  • призначається статичне поле класу,
  • використовується непостійне статичне поле, або
  • для класу вищого рівня виконується твердження про твердження, лексично вкладене в клас 1 .

Див. JLS 12.4.1 .

Також можна змусити клас ініціалізувати (якщо він ще не ініціалізований) за допомогою Class.forName(fqn, true, classLoader)або короткої формиClass.forName(fqn)


1 - Кінцева точка кулі була присутня в JLS для Java 6 через Java 8, але це було, мабуть, помилкою в специфікації. Нарешті було виправлено в Java 9 JLS: див. Джерело .


9
Однак є загальний підводний камінь. Примітиви та Strings заміщені та не посилаються на них. Якщо ви посилаєтесь на class Other { public static final int VAL = 10; }якийсь клас MyClass { private int = Other.VAL; }, клас Otherне завантажується. Натомість компілятор просто замінить підсумкове поле під час компіляції.
Рафаель Вінтерхалтер

6
@RafaelWinterhalter - так ... це постійний випадок статичного поля.
Стівен C

2
@RafaelWinterhalter, це не вірно для всіх примітивів чи Stringзмінних "статичних кінцевих" , лише тих, ініціалізованих постійним виразом.
Lew Bloch

1
Так, і поля навіть не потрібно, staticпоки це звичайний випадок.
Рафаель Вінтерхалтер

1
Це та сама мова програмування. Так.
Стівен C

14

Статичні поля ініціалізуються під час ініціалізації "фази" завантаження класу (завантаження, зв'язування та ініціалізація), що включає статичні ініціалізатори та ініціалізацію його статичних полів. Статичні ініціалізатори виконуються у текстовому порядку, як визначено у класі.

Розглянемо приклад:

public class Test {

   static String sayHello()  {
      return a;
   }

   static String b = sayHello(); // a static method is called to assign value to b.
                                 // but its a has not been initialized yet.

   static String a = "hello";

   static String c = sayHello(); // assignes "hello" to variable c

    public static void main(String[] arg) throws Throwable {
         System.out.println(Test.b); // prints null
         System.out.println(Test.sayHello()); // prints "hello"
    }
}

Test.b друкує, nullоскільки коли sayHelloвиклик був у статичній області, статична змінна aне була ініціалізована.


6
Строго кажучи, ініціалізація не є "фазою" завантаження класу. Дійсно, деякі класи можуть бути завантажені, але ніколи не ініціалізовані, якщо програма насправді не використовує їх.
Стівен C

@Stephen C Ви маєте рацію, я використав це через відсутність кращого терміна, можливо, я його процитую.
naikus

@StephenC це означає, що під час завантаження класу він призначає пам'ять статичним змінним (& методам), але ці статичні змінні не ініціалізуються зі значеннями, наданими в коді? тому що тут здається, коли b-> sayHello () -> a, 'a' є в пам'яті, але значення йому ще не присвоєно.
Шаббір Ессаджі

В основному, так.
Стівен C

1

Так, всі статичні ініціалізатори запускаються до першого доступу до класу. Якби це було інакше, я б назвав це помилкою.


Існують способи посилання на клас без ініціалізації.
Lew Bloch
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.