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

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

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

Никита Рыбак
источник
Есть способы ссылаться на класс без его инициализации.
Лью Блох