Когда выполняется статический блок класса?

У меня есть 2 баночки, назовем их a.jar и b.jar.

b.jar зависит от a.jar.

В a.jar я определил класс, назовем его StaticClass. В StaticClass я определил статический блок, вызвав метод с именем «init»:

public class StaticClass {
  static {
    init();
  } 

  public void static init () {
    // do some initialization here
  }
}

в b.jar у меня есть main, поэтому в основном я ожидаю, что был вызван метод init (), но на самом деле это не так. Я подозреваю, что это связано с тем, что StaticClass не был загружен jvm, может ли кто-нибудь сказать мне

  1. Мой вывод верен?
  2. Что заставляет jvm загружать класс?
  3. Как я могу заставить статический блок выполняться автоматически?

Спасибо


person Leon    schedule 03.02.2012    source источник
comment
Вам нужно будет где-то использовать свой StaticClass, чтобы он был загружен и инициализирован.   -  person Kris    schedule 03.02.2012
comment
Похоже, это может ответить на ваш вопрос.   -  person Andreas Baus    schedule 03.02.2012
comment
возможный дубликат: stackoverflow.com/questions/2007666/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 12.02.2015


Ответы (9)


Да, ты прав. Блоки статической инициализации запускаются, когда JVM (точнее, загрузчик классов) загружает StaticClass (что происходит при первой ссылке в коде).

Вы можете принудительно вызвать этот метод, явно вызвав StaticClass.init(), что предпочтительнее, чем полагаться на JVM.

Вы также можете попробовать использовать Class.forName(String), чтобы заставить JVM загружать класс и вызывать его статические блоки.

person ŁukaszBachman    schedule 03.02.2012
comment
что происходит при первой ссылке в коде - не всегда. Доступ к статическому примитивному типу, похоже, не запускает статические блоки. - person ; 08.08.2016
comment
статические блоки инициализации запускаются, когда JVM загружает StaticClass` --- неверно, загрузка класса отличается от инициализации класса. - person Marko Topolnik; 15.09.2016
comment
что происходит при первой ссылке в коде --- неверно, реализация может решить, когда загружать класс. Ссылка на класс - это только крайний срок, когда он обязательно должен быть загружен. - person Marko Topolnik; 15.09.2016
comment
@MarkoTopolnik прав. Блоки статической инициализации запускаются, когда JVM загружает неправильный оператор StaticClass. статические блоки выполняются во время инициализации класса. что предпочтительнее полагаться на JVM, это еще одно запутанное утверждение, здесь нет ничего общего с «полагаться» в случае StaticClass.init (), это просто вызов статического метода. - person Shafin Mahmud; 09.11.2016
comment
@hthserhs Публичные статические конечные примитивные типы и строки встраиваются во время javac. Следовательно, с точки зрения JVM доступа на самом деле нет. В итоге поведение понятно. Я просто хочу добавить контекст. То, что вы сказали, безусловно, правильно. - person Haozhun; 18.09.2020

Да, вы правы, поскольку вы не используете свой StaticClass, он не загружается vm и, следовательно, init() никогда не выполняется.

Что касается вашего второго вопроса, вам, вероятно, придется пойти тяжелым путем и просканировать все доступные классы и загрузить их.

https://stackoverflow.com/a/3223019/393657

person stryba    schedule 03.02.2012
comment
+1 за подсказку о сканировании всех классов и их автоматической инициализации. Может быть полезно использовать интерфейс / аннотацию маркера для классов, статический инициализатор которых должен выполняться автоматически (или любой другой определенный статический метод). Как сказано в связанной теме: Google Reflections может быть способом сделать это без особых хлопот. - person Thomas; 03.02.2012

Во-первых, загрузка класса отличается от инициализации класса. Для тех, кто ищет объяснения из Спецификации языка Java, когда выполняется статический блок - вот он.

JLS §8.7 говорит тот :

Статический инициализатор, объявленный в классе, выполняется при инициализации класса (§12.4.2).

Так что же означает инициализация? Обратимся к JLS §12.4. 2. Это описывает подробную процедуру инициализации. Однако точка JLS §12.4.1 может быть более подходящим здесь. В нем говорится, что:

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
  • Итак, чтобы блок статического инициализатора выполнялся автоматически, вы должны принудительно выполнить одну из этих опций.

    person Michał Krzywański    schedule 19.07.2019
    comment
    Интересно, можем ли мы предположить, что: class инициализируется, когда на него ссылаются по имени в уже запущенном коде. - person Pawel Dubiel; 27.09.2019

    Вы правы, проще всего получить доступ к классу, например сделать

    StaticClass.class.newInstance();

    Или что-то в этом роде в вашем основном методе. Это обеспечит загрузку класса загрузчиком классов.

    person Hiery Nomus    schedule 03.02.2012

    Статический код выполняется при ссылке на ваш класс (StaticClass, я думаю).

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

    person C.Champagne    schedule 03.02.2012

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

    person Shafin Mahmud    schedule 09.11.2016

    Да, статический инициализатор будет выполнен при загрузке класса. Обычно это происходит, когда вы впервые обращаетесь к классу в контексте загрузки класса.

    person Thomas    schedule 03.02.2012

    в классе основного метода b.jar должен расширяться этот StaticClass, а затем автоматически вызываются статический блок и init ()

    person santoshbharat    schedule 18.03.2013

    Добавляем еще:

    статический блок будет выполнен, когда jvm загрузит класс.

    Здесь, в вашем примере, вы можете вызвать init() метод своего StaticClass, задав класс

    как StaticClass staticClass = new StaticClass ();

    or

    StaticClass.class.newInstance(); это предпочтительнее

    person AhsanAli Nandoliya    schedule 20.05.2013
    comment
    Почему «так предпочтительнее»? - person user207421; 29.01.2017