Когда происходит инициализация статического класса?


110

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

Что, если я вызову статический метод? Он также запускает все статические блоки? До метода?


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

Ответы:


156

Статическая инициализация класса обычно происходит непосредственно перед первым возникновением одного из следующих событий:

  • создается экземпляр класса,
  • вызывается статический метод класса,
  • назначается статическое поле класса,
  • используется непостоянное статическое поле, или
  • для класса верхнего уровня выполняется оператор assert, лексически вложенный в класс 1 .

См. JLS 12.4.1 .

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


1 - Последний пункт маркированного списка присутствовал в JLS для Java 6–8, но, по-видимому, это была ошибка в спецификации. Это было окончательно исправлено в Java 9 JLS: см. Исходный код .


9
Однако есть распространенная ошибка. Примитивы и Strings заменяются и не упоминаются. Если вы ссылаетесь на class Other { public static final int VAL = 10; }какой-либо класс MyClass { private int = Other.VAL; }, Otherон не загружается. Вместо этого компилятор просто подставит последнее поле во время компиляции.
Рафаэль Винтерхальтер

6
@RafaelWinterhalter - да ... это случай постоянного статического поля.
Stephen C

2
@RafaelWinterhalter, это не верно для всех примитивов или Stringпеременных 'static final' , только для тех, которые инициализированы константным выражением.
Лью Блох

1
Да и поле даже не нужно, staticпока это обычное дело.
Рафаэль Винтерхальтер

1
Это тот же язык программирования. Да.
Стивен С.

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
Строго говоря, инициализация не является «фазой» загрузки класса. В самом деле, некоторые классы могут быть загружены, но никогда не инициализированы, если приложение фактически не использует их.
Stephen C

@Stephen C Вы правы, я использовал его из-за отсутствия лучшего термина, может быть, я его процитирую.
Найкус

@StephenC означает ли это, что во время загрузки класса он назначает память статическим переменным (и методам), но эти статические переменные не инициализируются значениями, указанными в коде? потому что здесь кажется, что когда b-> sayHello () -> a, 'a' находится в памяти, но значение ему еще не присвоено.
Шабир Эссаджи

В основном да.
Stephen C

1

Да, все статические инициализаторы запускаются перед первым обращением к классу. Если бы было иначе, я бы назвал это ошибкой.


Есть способы ссылаться на класс без его инициализации.
Лью Блох
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.