Что такое блок инициализации? - PullRequest
91 голосов
/ 21 октября 2010

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

Ответы [ 9 ]

164 голосов
/ 21 октября 2010

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

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

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

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.

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

89 голосов
/ 14 марта 2013

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

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

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

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

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

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

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

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

Пара дополнительных точек дляимейте в виду (пункт 1 - повторение ответа @ aioobe):

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

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

6 голосов
/ 03 июля 2014

хороший ответ от 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

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

3 голосов
/ 14 марта 2014

Пример кода, который утвержден в качестве ответа, является правильным, но я не согласен с ним.Он не показывает, что происходит, и я собираюсь показать вам хороший пример, чтобы понять, как на самом деле работает 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 без необходимости каких-либо экземпляров.Поэтому правильный доступ к статическим членам из внешнего класса (класс, в котором они не определены) заключается в использовании имени класса, следующего за точкой, а затем статического члена, к которому вы хотите получить доступ (шаблон: <CLASS_NAME>.<STATIC_VARIABLE_NAME>).

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

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

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

1 голос
/ 10 октября 2016

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

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

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

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

0 голосов
/ 13 мая 2019

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

0 голосов
/ 06 февраля 2015
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 голосов
/ 21 октября 2010

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

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 голосов
/ 21 октября 2010

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

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

...