В каком порядке выполняются статические блоки и блоки инициализации при использовании наследования?

У меня есть два класса Parent и Child

public class Parent {    
    public Parent() {
        System.out.println("Parent Constructor");
    }    
    static {
        System.out.println("Parent static block");    
    }    
    {
        System.out.println("Parent initialisation  block");
    }
}

public class Child extends Parent {    
    {
        System.out.println("Child initialisation block");
    }
    static {
        System.out.println("Child static block");
    }

    public Child() {
        System.out.println("Child Constructor");
    }    
    public static void main(String[] args) {
        new Child();    
    }
}

Вывод приведенного выше кода будет

Parent static block
Child static block
Parent initialization  block
Parent Constructor
Child initialization block
Child Constructor

Почему Java выполняет код именно в таком порядке? Какие правила определяют порядок выполнения?


person CKR666    schedule 24.10.2013    source источник
comment
В более новой версии Java (1.7 и выше) JVM выдает исключение времени выполнения, поскольку не находит основной метод в классе, даже если у вас есть статический блок.   -  person lft93ryt    schedule 27.01.2017


Ответы (11)


Я учусь визуально, поэтому вот визуальное представление порядка в виде SSCCE:

public class Example {

    static {
        step(1);
    }

    public static int step_2 = step(2);
    public int step_8 = step(8);

    public Example(int unused) {
        super();
        step(10);
    }

    {
        step(9);
    }

    // Just for demonstration purposes:
    public static int step(int step) {
        System.out.println("Step " + step);
        return step;
    }
}
public class ExampleSubclass extends Example {

    {
        step(11);
    }

    public static int step_3 = step(3);
    public int step_12 = step(12);

    static {
        step(4);
    }

    public ExampleSubclass(int unused) {
        super(step(7));
        step(13);
    }

    public static void main(String[] args) {
        step(5);
        new ExampleSubclass(step(6));
        step(14);
    }
}

Это печатает:

Step 1
Step 2
Step 3
Step 4
Step 5
Step 6
Step 7
Step 8
Step 9
Step 10
Step 11
Step 12
Step 13
Step 14

Имейте в виду, что порядок частей static имеет значение; оглянитесь назад на разницу между порядком вещей Example static и ExampleSubclass.

Также обратите внимание, что блок инициализации экземпляра всегда выполняется сразу после вызова super() в конструкторе (даже если этот вызов подразумевается/пропускается), независимо от порядка. Однако порядок между блоком инициализации и инициализатором поля имеет значение.

person Ky Leggiero    schedule 25.01.2016
comment
Пожалуйста, сопровождайте любые отрицательные голоса причиной, чтобы я знал, как писать лучшие ответы в будущем :) - person Ky Leggiero; 03.02.2018
comment
«Блок инициализации экземпляра всегда выполняется перед конструктором»: нет, он выполняется во время конструктора после вызова super(). Ваш вывод не опровергает этого. Он выполняется перед любыми строками кода в коснтрукто после super(). Не то же самое. - person user207421; 28.04.2020
comment
Спасибо, что сообщили мне, @ user207421. У меня проблемы с визуализацией того, что вы пытаетесь сказать; когда я помещаю еще один вызов step() перед super() в конструкторе, я получаю следующие ошибки: photos.app.goo.gl /9ToHkTVuAutpjrbm7 - поэтому я не знаю, как проверить, происходит ли что-то до вызова super() - person Ky Leggiero; 28.04.2020
comment
Ага, кажется, я понял! Я обновлю свой вопрос. Спасибо, @user207421! - person Ky Leggiero; 28.04.2020

В игре есть несколько правил

  • статические блоки всегда запускаются до создания объекта, поэтому вы видите сообщения печати как от родительских, так и от дочерних статических блоков.
  • теперь, когда вы вызываете конструктор подкласса (дочернего), этот конструктор неявно вызывает super(); перед выполнением собственного конструктора. Блок инициализации вступает в действие еще до вызова конструктора, поэтому он вызывается первым. Итак, теперь ваш родитель создан, и программа может продолжить создание дочернего класса, который будет проходить тот же процесс.

Пояснения:

  1. Статический блок родителя выполняется первым, потому что он загружается первым, а статические блоки вызываются при загрузке класса.
person Petr Mensik    schedule 24.10.2013
comment
потому что базовый класс для производного класса является родительским классом, созданным вами - person Ankush Bist; 13.06.2016
comment
Блоки инициализации экземпляра вступают в действие во время конструктора после выполнения super(). - person user207421; 28.04.2020

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

во-вторых, перейдите к разделу Статический блок или блок инициализатора в Java? & прочитайте принятый ответ там.

Редактировать:

  1. Выполнение происходит способом SIC - статическим, (не статическим) инициализатором и конструктором.
  2. (Не статический) Инициализатор копируется в каждый конструктор - В ТОП! (отсюда строки 3/4/5/6)
  3. Перед инициализацией класса необходимо инициализировать его непосредственный суперкласс — http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4 (поэтому родительский статический блок появляется первым).
person Raúl    schedule 24.10.2013

  • Статические блоки инициализации выполняются во время загрузки класса.
  • В иерархии классов порядок выполнения статических блоков инициализации будет начинаться с класса верхнего уровня.
  • В классе порядок выполнения статического блока сверху вниз.
  • Приведенное выше правило применяется независимо от того, где в классе присутствует статический блок.

(В вашем коде сначала будут выполняться родительские статические блоки, а затем статические блоки дочернего класса.)

  • Instance init blocks will be executed after the call to the super(); in the constructor.
    • Always super(); is the very first statement in a default constructor.

В вашем коде при создании дочернего объекта:

  • Выполняется конструктор по умолчанию класса Child.
  • Он вызовет функцию super(); конструктор.
  • Затем выполняется конструктор суперкласса.
  • Родительский класс выполнит свой super(); вызов.
  • После этого выполняются блоки инициализации экземпляра в родительском классе (сверху вниз).
  • Затем выполняется код внутри конструктора (если он есть).
  • Затем он вернется к классу Child и выполнит блоки инициализации экземпляра класса Child.
  • Наконец, код в дочернем конструкторе выполняется (если существует).
person Sayanthan Mahendran    schedule 21.06.2018
comment
Ваш второй пункт правилен, а ваш третий пункт противоречит ему, поэтому он неверен. - person user207421; 28.04.2020

Статический блок в java выполняется перед основным методом. Если мы объявляем статический блок в классе Java, он выполняется при загрузке класса. Это инициализация со статическими переменными. Он в основном используется в JDBC. Статический блок в java выполняется каждый раз при загрузке класса. Это также известно как статический блок инициализации. Статический блок в java инициализируется при загрузке класса в память, то есть когда JVM считывает байт-код. Инициализация может быть чем угодно; это может быть инициализация переменных или что-то еще, что должно быть общим для всех объектов этого класса. Статический блок — это обычный блок кода, заключенный в фигурные скобки {}, которому предшествует ключевое слово static.

поэтому статический блок выполняется первым.

Блоки инициализации экземпляра: запускается каждый раз при создании экземпляра класса.

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

затем выполняется конструктор

person rohan kamat    schedule 24.10.2013
comment
почему статический блок родительского класса выполняется первым....? Сначала я загружаю дочерний класс? - person CKR666; 24.10.2013
comment
@ CKR666 Загрузка класса chld требует загрузки его родителей. Было бы бессмысленно сначала не инициализировать родителя. - person user207421; 28.04.2020

Было бы очень полезно проверить процесс создания объекта с помощью пошагового отладчика, имея представление, в котором вы можете видеть, как ваш объект проходит через фазы. Я нашел это очень полезным для прояснения перспективы с более высокой точки зрения. Eclipse может помочь вам в этом с помощью отладчика.

person Mihai Savin    schedule 10.12.2015

Просто хотел поделиться своими выводами. Я прочитал в одном из ответов в другом потоке, что статические блоки выполняются сначала перед статическими полями, что неверно. Это зависит от того, что будет первым, статическое поле или статический блок. Посмотрите на приведенный ниже код. Он попытается поставить вещи в перспективе.

  1. JVM ищет класс с общедоступным static void main(String args[]), чтобы он мог загрузить этот класс.
  2. Затем он инициализирует статические поля этого класса (если они стоят перед статическими блоками). Эти поля могут вызывать статические методы того или иного класса. Если они вызывают статический метод этого класса, то этот метод обслуживается. Если они вызывают статический метод другого класса, то сначала инициализируются статические поля или блоки этого класса (в зависимости от того, что наступит раньше), а затем обслуживается вызов этого метода.
  3. Затем он переходит к статическим блокам.
  4. Он возвращается к основному методу.

    class TestLab {
    static int method(String a) {
        System.out.println("in static method of TestLab" + " Coming from " + a);
        System.out.println("b is " + b);
        return 6;
    }
    
    static int a = method("Line 11");
    static int b = 7;
    
    TestLab() {
        System.out.println("Inside test lab constructor");
    }
    
    static {
        System.out.println("In static block of TestLab");
    }
    
    }
    
    public class Test1 {
    public static void main(String[] args) {
        System.out.println("inside main method of Test 1");
        int a = TestLab.method("Line 26");
    }
    
    // static Test ref=new Test();
    Test1() {
        System.out.println("Default Constructor of Test1");
    }
    
    {
        System.out.println("In instance block of Test1");
    }
    static int d = TestLab.method("Line 37");
    static int e = methodOfTest1();
    static {
        System.out.println("In Static Block of Test1");
    }
    
    static int methodOfTest1() {
        System.out.println("inside static method:mehtodOfTest1()");
        return 3;
    }
    }
    

Вот результат:

in static method of TestLab Coming from Line 11
b is 0
In static block of TestLab
in static method of TestLab Coming from Line 37
b is 7
inside static method:mehtodOfTest1()
In Static Block of Test1
inside main method of Test 1
in static method of TestLab Coming from Line 26
b is 7
person pragun    schedule 16.03.2017
comment
Вы сами себе противоречите. Статические поля и блоки инициализатора выполняются в том порядке, в котором они появляются в исходном файле, независимо от того, какой именно. - person user207421; 28.04.2020
comment
@ user207421, извините, я вас не понял. Я написал ниже то, что было проиллюстрировано в выводе: Это зависит от того, что будет первым, статическое поле или статический блок - person pragun; 21.12.2020

Вот что я обнаружил, готовясь к сертификации.

Пока мы запускаем класс, происходит инициализация первых статических блоков/статических переменных. Если есть несколько статических блоков, он будет выполнять их в том порядке, в котором они появляются,

Затем он выполнит инициализацию блоков инициализации / инициализацию переменной экземпляра. Если имеется несколько инициализационных блоков / инициализации переменной, он выполнит их в том порядке, в котором они появляются,

После этого он заглянет в конструктор.

person PRAVEEN PS    schedule 14.09.2017

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

person Sunil Kumar Jha    schedule 16.07.2015

поток управления

статический блок -> блок инициализации -> и, наконец, конструктор.

статический блок -> Этот статический блок будет выполняться только один раз, когда управление перейдет к классу. (JVM загружает этот класс)

Блок инициализации -> Этот блок инициализации будет выполняться всякий раз, когда новый объект создается для класса (он будет выполняться из второго оператора конструктора, а затем следующих операторов конструктора — помните, что первый оператор конструктора будет Super ()/это())

Конструктор -> Это будет получаться всякий раз, когда создается новый объект.

person Prakash VL    schedule 03.10.2016

  1. Статический блок инициализации выполняется во время загрузки класса только один раз.
  2. Блок инициализации выполняется каждый раз перед созданием объекта класса.

Узнайте больше из этого видео: Учебное пособие по Java от Раджана Джейна: статический блок инициализации и блок инициализации в java Видео14 — YouTube

person Java Tutorial    schedule 04.11.2018