В каком порядке выполняются блоки инициализатора static / instance в Java?
говорят, что проект содержит несколько классов, каждый из которых имеет статический блок инициализации. В каком порядке эти блоки работают? Я знаю, что внутри класса такие блоки выполняются в том порядке, в котором они появляются в коде. Я читал, что это то же самое в разных классах, но некоторые примеры кода, которые я написал, не согласны с этим. Я использовал этот код:
package pkg;
public class LoadTest {
public static void main(String[] args) {
System.out.println("START");
new Child();
System.out.println("END");
}
}
class Parent extends Grandparent {
// Instance init block
{
System.out.println("instance - parent");
}
// Constructor
public Parent() {
System.out.println("constructor - parent");
}
// Static init block
static {
System.out.println("static - parent");
}
}
class Grandparent {
// Static init block
static {
System.out.println("static - grandparent");
}
// Instance init block
{
System.out.println("instance - grandparent");
}
// Constructor
public Grandparent() {
System.out.println("constructor - grandparent");
}
}
class Child extends Parent {
// Constructor
public Child() {
System.out.println("constructor - child");
}
// Static init block
static {
System.out.println("static - child");
}
// Instance init block
{
System.out.println("instance - child");
}
}
и получил этот выход:
START
статические-бабушки и дедушки
статические - родитель
статический - ребенок
пример-бабушка с дедушкой
конструктор-дедушка
экземпляр-родитель
конструктор - родитель
экземпляр - ребенок
конструктор - ребенок
Конец
EDIT:
Я изменил свой пример кода, добавив Это для загрузки.java:
class IAmAClassThatIsNeverUsed {
// Constructor
public IAmAClassThatIsNeverUsed() {
System.out.println("constructor - IAACTINU");
}
// Instance init block
{
System.out.println("instance - IAACTINU");
}
// Static init block
static {
System.out.println("static - IAACTINU");
}
}
как следует из имени класса, я никогда не ссылался на новый класс нигде. Новая программа произвела тот же результат, что и старая.
7 ответов:
статический инициализатор для класса запускается при первом обращении к классу либо для создания экземпляра, либо для доступа к статическому методу или полю.
Итак, для нескольких классов это полностью зависит от кода, который запускается, чтобы заставить эти классы загружаться.
см. раздел 12.4 и 12.5 в JLS version 8, они подробно рассказывают обо всем этом (12.4 для статических и 12.5 для переменных экземпляра).
для статической инициализации (раздел 12.4):
класс или тип интерфейса T будет инициализирован непосредственно перед первым появлением любого из следующих:
- T-это класс, и создается экземпляр T.
- T-это класс и статический метод, объявленный T вызываемый.
- назначается статическое поле, объявленное T.
- используется статическое поле, объявленное T, и это поле не является постоянной переменной (§4.12.4).
- T-это класс верхнего уровня (§7.6), и выполняется оператор assert (§14.10), лексически вложенный в T (§8.1.3).
(и несколько предложений слова ласки)
ответы Кита и Криса оба великолепны, я просто добавляю еще несколько деталей для моего конкретного вопроса.
статические блоки инициализации выполняются в том порядке, в котором их классы инициализируются. Итак, что это за порядок? Согласно JLS 12.4.1:
класс или тип интерфейса T будет инициализирован непосредственно перед первым появлением любого из следующих:
- T-это класс, и создается экземпляр T.
- T-это класс, и вызывается статический метод, объявленный T.
- назначается статическое поле, объявленное T.
- используется статическое поле, объявленное T, и это поле не является постоянной переменной (§4.12.4).
- T-класс верхнего уровня, и выполняется оператор assert (§14.10), лексически вложенный в T.
вызов определенных отражающих методов в классе Class и в пакете java.ленг.отражение также вызывает класс или инициализация интерфейса. Класс или интерфейс не будут инициализированы ни при каких других обстоятельствах.
чтобы проиллюстрировать, вот пошаговое руководство того, что происходит в Примере:
- введите main
- печать "запустить"
- попытка создать первый экземпляр Child, который требует инициализации Child
- попытка инициализации дочернего вызывает инициализацию Родитель
- попытка инициализации родителя вызывает инициализацию бабушки и дедушки
- в начале инициализации бабушки и дедушки выполняется статический блок инициализации бабушки и дедушки
- технически объект получает последнее слово в цепочке инициализации в силу того, что он является родителем бабушки и дедушки, но ему нечего добавить
- после статического блока инициализации бабушки и дедушки заканчивается, программа возвращается к родительскому статическому блоку инициализации
- после завершения блока статической инициализации родителя программа возвращается к блоку статической инициализации ребенка
- В этот момент ребенок инициализируется, поэтому его конструктор может продолжить
- поскольку IAmAClassThatIsNeverUsed никогда не ссылается, ни один из его кода никогда не выполняется, включая статические блоки инициализатора
- остальная часть это пошаговое руководство не касается статических инициализаторов и включено только для полноты
- конструктор ребенка неявно вызывает super () (т. е. конструктор родителя)
- родительский конструктор неявно вызывает super () (т. е. конструктор бабушки и дедушки)
- конструктор бабушки и дедушки делает то же самое, что не имеет никакого эффекта (опять же, объект не имеет ничего общего)
- сразу после вызова конструктора бабушки и дедушки в super () приходит Блок инициализатора экземпляра бабушки и дедушки
- остальная часть конструктора конструктора бабушки и дедушки запускается, и конструктор завершается
- программа возвращается к родительскому конструктору, сразу после его вызова super () (т. е. конструктор бабушки и дедушки) разрешает
- как и выше, инициализатор родительского экземпляра делает свое дело, и его конструктор завершает
- аналогично, программа возвращает и завершает ребенка конструктор
- в этот момент объект был инстанцирован
- печатать "конец"
- завершить нормально
инициализация класса состоит из выполнения его статические инициализаторы и инициализаторы для статических полей (переменных класса), объявленного в классе.
инициализация интерфейса заключается в выполнении инициализаторов для полей (констант), объявленных в интерфейсе.
перед инициализацией класса должен быть инициализирован его прямой суперкласс, но интерфейсы, реализуемые классом, не инициализируются. Аналогично, суперинтерфейсы интерфейса не инициализируются до инициализации интерфейса.
вы можете иметь несколько статических и инициализаторы экземпляра в одном классе, поэтому
- статические инициализаторы вызываются в текстовом порядке, в котором они объявлены (от 12.4.2)
- инициализаторы экземпляра в текстовом порядке, в котором они объявлены (с 12.5)
каждый выполняется, как если бы это был один блок.
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
пожалуйста, проверьте документацию java.
тогда четко указано, как бы ни были статические блоки, они будут выполняться как один блок в том порядке, в котором они появляются
и
мое понимание здесь-это Java-это просмотр кода
static{ i=1; i=2; }
static int i;
вот почему вы получаете выход 2
Надежда это полезно