Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

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.

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

Ответ 2

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

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

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

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

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

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

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

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

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

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

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

Ответ 3

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

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

Ответ 4

Пример кода, который одобрен в качестве ответа здесь, является правильным, но я не согласен с ним. Он не показывает, что происходит, и я покажу вам хороший пример, чтобы понять, как работает 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, но перед печатью "Constructor" он переходит к блоку нестатической инициализации. Для лучшего понимания отлаживаем его с помощью некоторой IDE, я предпочитаю Eclipse.

Ответ 5

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

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

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

Мы используем Static Block в Java.

Ответ 6

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

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

Ответ 7

Чтобы узнать, как использовать статический блок инициализации, обратитесь к исходному коду Class.forName, также в этой статье используйте http://cephas.net/blog/2005/07/31/java-classfornamestring-classname-and-jdbc/, они используют блок инициализации для загрузки динамического класса.

Ответ 8

Вопрос не совсем ясен, но здесь приводится краткое описание способов инициализации данных в объекте. Предположим, что у вас есть класс 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;
    }
}

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

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

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

Ответ 9

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

Ответ 10

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

class Employee { 
 { 
 System.out.println("Employee:initializer"); 
 } 
}

Ответ 11

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