it-swarm.com.ru

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

У меня два класса 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 выполняет код в таком порядке? Какие правила определяют порядок исполнения?

76
CKR666

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

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

Пояснения:

  1. Статический блок parent выполняется первым, потому что он загружается первым и статические блоки вызываются при загрузке класса. 
48
Petr Mensik

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

public class Example {

  static {
    step(1);
  }

  public static int step_1 = step(2);
  public int step_6 = step(6);

  public Example() {
    step(8);
  }

  {
    step(7);
  }

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

public class ExampleSubclass extends Example {

  {
    step(9);
  }

  public static int step_3 = step(3);
  public int step_10 = step(10);

  static {
    step(4);
  }

  public ExampleSubclass() {
    step(11);
  }

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

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

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

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

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

38
Ben Leggiero

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

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

Правка:

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

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

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

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

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

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

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

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

  • Блоки инициализации экземпляра будут выполнены после вызова super (); в конструкторе .
    • Всегда супер (); это самый первый оператор в конструкторе по умолчанию.

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

  • Конструктор по умолчанию класса Child исполняется. 
  • Это вызовет супер (); конструктор. 
  • Затем выполняется конструктор суперкласса. 
  • Родительский класс выполнит свой super (); вызов. 
  • После этого исполняются блоки init экземпляра в классе Parent (сверху вниз). 
  • Затем выполняется код внутри конструктора (если есть). 
  • Затем он вернется в класс Child и выполнит блоки инициализации экземпляра класса Child. 
  • Наконец код в дочернем конструкторе выполняется (если существует).
4
Sayanthan Mahendran

Вот что я нашел при подготовке к сертификации.

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

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

После этого он будет смотреть в конструктор.

3
PRAVEEN PS

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

3
Mihai Savin

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

  1. JVM ищет класс, который имеет открытый статический 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
3
pragun

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

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

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

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

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

1
Prakash VL

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

ссылка: - https://www.youtube.com/watch?v=6qG3JE0FbgA&t=2s

0
Java Tutorial

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

0
Sunil Kumar Jha