статический блок против блока инициализатора против конструктора в наследовании

Я нашел этот пример и хочу понять его логику? как конструкторы и статические блоки и блоки инициализатора работают в наследовании? на каком этапе вызывается каждый?

public class Parent {

    static {
        System.out.println("i am Parent 3");
    }

    {
        System.out.println("i am parent 2");
    }

    public Parent() {
        System.out.println("i am parent 1");
    }

}

public class Son extends Parent {

    static {System.out.println("i am son 3");}
    {System.out.println("i am son 2");}

    public Son() {
        System.out.println("i am son 1");
    }

    public static void main(String[] args) {
        new Son();
    }
}

вывод:

i am Parent 3
i am son 3
i am parent 2
i am parent 1
i am son 2
i am son 1

person oussama.elhadri    schedule 01.02.2014    source источник
comment
Вы уже отправили ответ на свой вопрос.   -  person jax    schedule 02.02.2014
comment
Вместо использования чисел используйте собственные имена, такие как статический блок, блок инициализатора, конструктор, чтобы сделать вывод более понятным.   -  person Pshemo    schedule 02.02.2014


Ответы (4)


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

Статические инициализаторы и инициализаторы экземпляра описаны в Спецификации языка Java

person JB Nizet    schedule 01.02.2014
comment
И, очевидно, вызывается перед конструктором. - person apnorton; 02.02.2014
comment
@anorton Перед созданием экземпляра класса необходимо инициализировать его. - person user207421; 02.02.2014

Вы должны знать, что

  1. первая инструкция в конструкторе вызывает конструктор его родительского класса super(params) или если вы хотите использовать конструктор по умолчанию super(). В случае конструктора по умолчанию вам не нужно писать его явно.
  2. код в блоке инициализатора перемещается в каждый конструктор сразу после вызова super(...)
  3. статический блок выполняется, когда класс инициализируется, что выполняется после его полной загрузки (с его родительскими классами) JVM.

Итак, классы компилируются в классы, подобные этому.

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

    public Parent() {
        super();
        {
            System.out.println("Parent initializer block");
        }
        System.out.println("Parent constructor");
    }

}

public class Son extends Parent {

    static {
        System.out.println("Son static block");
    }

    public Son() {
        super();
        {
            System.out.println("Son initializer block");
        }
        System.out.println("Son constructor");
    }

    public static void main(String[] args) {
        new Son();
    }
}

Чтобы иметь возможность выполнять метод main из класса Son, JVM необходимо загрузить код этого класса (и классов, которые он расширяет). После полной загрузки класса JVM инициализирует его статическое содержимое, которое включает выполнение статических блоков (да, в одном классе может быть более одного статического блока). Для полной загрузки Son класса JVM необходимо знать подробности о своем родительском классе, чтобы он полностью загрузил Parent класс до Son, что означает, что он также будет выполнять свои статические блоки перед статическими блоками в классе Son.

Таким образом, результат будет выглядеть так:

  • Parent static block
  • Son static block

Теперь в методе main вы вызываете конструктор класса Son через new Son(), код которого выглядит как

super();
{
    System.out.println("Son initializer block");
}
System.out.println("Son constructor");

Поскольку его super() относятся к конструктору класса Parent, который

super();// this will invoke Object constructor since Parent 
        // doesn't extend anything (which means it extends Object class)
{
    System.out.println("Parent initializer block");
}
System.out.println("Parent constructor");

в результате вы увидите

  • Parent initializer block
  • Parent constructor

Это обрабатывает Parent#constructor(), выполняемое с super(), поэтому теперь вы увидите код из конструктора Son после super(), который сгенерирует

  • Son initializer block
  • Son constructor

Чтобы увидеть, что классы будут загружены еще до того, как вы используете Son конструктор или даже main метод, вы можете просто распечатать что-нибудь перед использованием Son конструктора, например

System.out.println("ABC                      // before new Son()");
new Son();

что приведет к

Parent static block
Son static block
ABC                      // before new Son()
Parent initializer block
Parent constructor
Son initializer block
Son constructor
person Pshemo    schedule 01.02.2014
comment
В этом нет никакого «пока». Сначала вызывается статический инициализатор, а затем - один раз при первой загрузке и инициализации класса, что может занять несколько часов или недель до вызова любого конструктора. Вы этого не прояснили. - person user207421; 02.02.2014
comment
@EJP Вы правы, удалил. - person Pshemo; 02.02.2014
comment
Я не просто комментирую эти три слова. Вы вообще не отделили загрузку класса и инициализацию от построения. - person user207421; 02.02.2014
comment
Обратите внимание, что Son должен быть загружен JVM для вызова main. - person Sotirios Delimanolis; 02.02.2014
comment
@SotiriosDelimanolis Именно так. Никакого отношения к строительству. - person user207421; 02.02.2014
comment
@SotiriosDelimanolis EJP, вы правы, над этим работаете. - person Pshemo; 02.02.2014

Статический блок вызывается, когда ваш класс загружается, и ваш класс сначала загружается загрузчиком классов в jvm, поэтому сначала они выполняются

затем вы создаете объект, поэтому ваш родительский блок инициализации вызывается, затем ваш родительский конструктор из-за цепочки конструкторов в java, затем блок инициализации производного класса, затем конструктор производного класса

person Girish    schedule 01.02.2014

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

Статический инициализатор - это эквивалент конструктора в статическом контексте. Вы наверняка увидите это чаще, чем инициализатор экземпляра.

person Vivek Vermani    schedule 01.02.2014