it-swarm.com.ru

Что такое блок инициализации?

Мы можем поместить код в конструктор, метод или блок инициализации. Какая польза от блока инициализации? Необходимо ли, чтобы это было в каждой Java-программе? 

83
Sumithra

Прежде всего, есть два типа блоков инициализации :

  • экземпляры блоков инициализации и
  • статические блоки инициализации.

Этот код должен иллюстрировать их использование и в каком порядке они выполняются:

public class Test {

    static int staticVariable;
    int nonStaticVariable;        

    // Static initialization block:
    // Runs once (when the class is initialized)
    static {
        System.out.println("Static initalization.");
        staticVariable = 5;
    }

    // Instance initialization block:
    // Runs each time you instantiate an object
    {
        System.out.println("Instance initialization.");
        nonStaticVariable = 7;
    }

    public Test() {
        System.out.println("Constructor.");
    }

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

Печать:

Static initalization.
Instance initialization.
Constructor.
Instance initialization.
Constructor.

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

157
aioobe

хотел бы добавить к ответу @ aioobe

Порядок исполнения:

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

  2. статическая инициализация блоков класса

  3. блоки инициализации экземпляра суперклассов

  4. конструкторы суперклассов

  5. блоки инициализации экземпляра класса

  6. конструктор класса.

Несколько дополнительных моментов, которые нужно иметь в виду (пункт 1 - повторение ответа @ aioobe):

  1. Код в статическом блоке инициализации будет выполняться во время загрузки класса (и да, это означает, что только один раз для загрузки класса), до того, как будут созданы какие-либо экземпляры класса, и до того, как будут вызваны любые статические методы.

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

87
Biman Tripathy

Хороший ответ от aioobe Добавив еще несколько пунктов

public class StaticTest extends parent {
    static {
        System.out.println("inside satic block");
    }

    StaticTest() {
        System.out.println("inside constructor of child");
    }

    {
        System.out.println("inside initialization block");
    }

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

class parent {
    static {
        System.out.println("inside parent Static block");
    }
    {
        System.out.println("inside parent initialisation block");
    }

    parent() {
        System.out.println("inside parent constructor");
    }
}

это дает 

inside parent Static block
inside satic block
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside main

это как изложение очевидного, но кажется немного более ясным.

6
Gaurav

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

package test;

    class A {
        A() {
            print();
        }

        void print() {
            System.out.println("A");
        }
    }

    class B extends A {
        static int staticVariable2 = 123456;
        static int staticVariable;

        static
        {
            System.out.println(staticVariable2);
            System.out.println("Static Initialization block");
            staticVariable = Math.round(3.5f);
        }

        int instanceVariable;

        {
            System.out.println("Initialization block");
            instanceVariable = Math.round(3.5f);
            staticVariable = Math.round(3.5f);
        }

        B() {
            System.out.println("Constructor");
        }

        public static void main(String[] args) {
            A a = new B();
            a.print();
            System.out.println("main");
        }

        void print() {
            System.out.println(instanceVariable);
        }

        static void somethingElse() {
            System.out.println("Static method");
        }
    }

Прежде чем начать комментировать исходный код, я дам вам краткое объяснение статических переменных класса:

Во-первых, они называются переменными класса, они принадлежат классу, а не конкретному экземпляру класса. Все экземпляры класса совместно используют эту статическую (классовую) переменную. Каждая переменная имеет значение по умолчанию в зависимости от примитива или ссылочного типа. Другое дело, когда вы переназначаете статическую переменную в некоторых членах класса (блоки инициализации, конструкторы, методы, свойства) и, делая это, вы изменяете значение статической переменной не для конкретного экземпляра, вы меняете его для всех экземпляров. В заключение о статической части я скажу, что статические переменные класса создаются не тогда, когда вы впервые создаете экземпляр класса, они создаются при определении класса, они существуют в JVM без необходимости каких-либо экземпляров. Поэтому правильный доступ к статическим членам из внешнего класса (класс, в котором они не определены) заключается в использовании имени класса, следующего за точкой, а затем статического члена, к которому вы хотите получить доступ (template: <CLASS_NAME>.<STATIC_VARIABLE_NAME>).

Теперь давайте посмотрим на код выше:

Точка входа является основным методом - всего три строки кода. Я хочу сослаться на пример, который в настоящее время одобрен. В соответствии с этим первое, что должно быть напечатано после печати «Статический блок инициализации», это «Блок инициализации», и вот мое несогласие, блок нестатической инициализации не вызывается перед конструктором, он вызывается перед любой инициализацией конструкторов. класса, в котором определен блок инициализации. Конструктор класса - это первое, что задействуется при создании объекта (экземпляра класса), а затем при входе в конструктор первой вызываемой частью является либо неявный (по умолчанию) супер-конструктор, либо явный супер-конструктор, либо явный вызов другого перегруженного конструктор (но в какой-то момент, если есть цепочка перегруженных конструкторов, последний вызывает супер-конструктор, неявно или явно). 

Существует полиморфное создание объекта, но прежде чем войти в класс B и его основной метод, JVM инициализирует все переменные класса (статические), затем проходит через блоки статической инициализации, если таковые существуют, и затем входит в класс B и начинается с выполнение основного метода. Он переходит к конструктору класса B, а затем немедленно (неявно) вызывает конструктор класса A, используя полиморфизм, вызываемый в теле конструктора класса A метод (переопределенный метод), который определен в классе B, и в этом случае переменная с именем instanceVariable используется перед повторной инициализацией. После закрытия конструктора класса B поток возвращается в конструктор класса B, но перед печатью «Конструктор» он идет сначала в нестатический блок инициализации. Для лучшего понимания отладки с помощью некоторой IDE, я предпочитаю Eclipse.

3
nenito

Блок Initializer содержит код, который всегда выполняется при создании экземпляра. Он используется для объявления/инициализации общей части различных конструкторов класса. 

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

Что если мы хотим выполнить какой-то код один раз для всех объектов класса?

Мы используем статический блок в Java. 

1
roottraveller

Блоки инициализации выполняются всякий раз, когда класс инициализируется и перед вызовом конструкторов. Они обычно размещаются над конструкторами в фигурных скобках. Нет необходимости включать их в ваши классы.

Они обычно используются для инициализации ссылочных переменных. Это страница дает хорошее объяснение

0
Gaurav Saxena

Инициализм Отображает текст внутри элемента <abbr> с немного меньшим размером шрифта

0
Anandkumar Prajapati

Вопрос не совсем понятен, но вот краткое описание способов инициализации данных в объекте. Предположим, у вас есть класс A, который содержит список объектов.

1) Поместите начальные значения в декларацию поля:

class A {
    private List<Object> data = new ArrayList<Object>();
}

2) Назначьте начальные значения в конструкторе:

class A {
    private List<Object> data;
    public A() {
        data = new ArrayList<Object>();
    }
}

Они оба предполагают, что вы не хотите передавать «данные» в качестве аргумента конструктора.

Все становится немного сложнее, если вы смешиваете перегруженные конструкторы с внутренними данными, как описано выше. Рассматривать:

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        data = new ArrayList<Object>();
        name = "Default name";
        userFriendlyName = "Default user friendly name";
    }

    public B(String name) {
        data = new ArrayList<Object>();
        this.name = name;
        userFriendlyName = name;
    }

    public B(String name, String userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

Обратите внимание, что много повторяющегося кода. Вы можете исправить это, заставив конструкторы вызывать друг друга, или у вас может быть частный метод инициализации, который вызывает каждый конструктор:

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        this("Default name", "Default user friendly name");
    }

    public B(String name) {
        this(name, name);
    }

    public B(String name, String userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

или же

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        init("Default name", "Default user friendly name");
    }

    public B(String name) {
        init(name, name);
    }

    public B(String name, String userFriendlyName) {
        init(name, userFriendlyName);
    }

    private void init(String _name, String _userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

Два (более или менее) эквивалентны.

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

Правка: я интерпретировал ваш вопрос как «как я инициализирую переменные моего экземпляра», а не «как работают блоки инициализатора», так как блоки инициализатора являются относительно продвинутой концепцией, и из тона вопроса кажется, что вы спрашиваете о более простая концепция. Я могу ошибаться.

0
Cameron Skinner
public class StaticInitializationBlock {

    static int staticVariable;
    int instanceVariable;

    // Static Initialization Block
    static { 
        System.out.println("Static block");
        staticVariable = 5;

    }

    // Instance Initialization Block
    { 

        instanceVariable = 7;
        System.out.println("Instance Block");
        System.out.println(staticVariable);
        System.out.println(instanceVariable);

        staticVariable = 10;
    }


    public StaticInitializationBlock() { 

        System.out.println("Constructor");
    }

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

}

Результат:

Static block
Instance Block
5
7
Constructor
Instance Block
10
7
Constructor
0
Anıl Emre Özçelik