Блок инициализации (initialization block) — понятие в объектно-ориентированном программировании, в основном известное из языка Java, которое представляет собой последовательность команд, выполняемых при создании (загрузке) классов и объектов. Разработано, чтобы значительно увеличить мощность конструктора. Существуют два типа: статический блок инициализации, обычно называемый для краткости статический блок (static block), и динамический блок инициализации (instance block).

Мотивация При создании объекта выполняются различные команды, указанные в конструкторе. Иногда возникает необходимость расширения возможностей синтаксиса. Как правило, динамический блок существует только для удобства — он может быть легко заменен путем добавления функции загрузки и ее вызова из каждого конструктора. Однако статический блок в значительной степени увеличивает функциональность программы и поэтому используется намного чаще.

Статический блок инициализации Статический блок — это, в сущности, конструктор для всего класса. Его синтаксис: ... static { // Static block code } ... Он ставится между определениями полей и функциями класса. Команды будут выполняться в одном из двух случаев, том, который наступит раньше: При создании первого объекта класса в процессе работы программы, перед запуском конструктора. При первом вызове статической функции, перед выполнением. То есть код выполняется при первой загрузке класса. В предлагаемом примере нужно создать класс, моделирующий автомобили, произведённые конкретной компанией, и сопровождающий их в целях отслеживания остальной части их существования, включая ситуацию в данный момент времени, владельцев, историю ремонта и т. д. Каждый объект — это автомобиль, а в классе есть статическое поле, которое содержит базу данных всех автомобилей. Основано на структуре map, когда ключ — это модель автомобиля, а содержание — группа автомобилей этой модели. Следующий код демонстрирует использование статического блока инициализации: public class Car { static Map<String, Set<Car>> catalog; static { catalog = new HashMap<String, Set<Car>>(); catalog.put("model105", new HashSet<Car>()); catalog.put("model125", new HashSet<Car>()); catalog.put("model140", new HashSet<Car>()); catalog.put("model201", new HashSet<Car>()); } public Car (String model) { catalog.get(model).add(this); // ... } // ... } Строку 4 можно легко присоединить к строке 2, без необходимости в статическом блоке. Однако строки 5—8 показывают потребность в нём — возможность выполнять сложные команды на уровне класса, которые на уровне объекта появились бы в конструкторе.

Динамический блок инициализации Динамический блок представляет собой дополнение к конструктору. Его синтаксис: ... { // Instance block code } ... Он ставится между определениями полей и функциями класса. Команды будут выполняться при создании объекта. Динамический блок — это добавка для упрощения написания конструктора, и он не приносит дополнительной функциональности. Он позволяет сэкономить создание функции запуска и добавление её вызова из всех конструкторов. Например, фрагмент кода: public class Car { static int count = 0; public Car (String model) { init(); // ... } public Car (String model, Double price) { init(); // ...

private void init() { count++; System.out.println("Hello everyone, we have " + count + " cars now!"); } // ... } равнозначен коду: public class Car { static int count = 0; public Car (String model) { // ... } public Car (String model, Double price) { // ...

count++; System.out.println("Hello everyone, we have " + count + " cars now!"); } // ... }

Порядок выполнения загрузки При разработке языка Java был установлен постоянный порядок действий при загрузке. Во время загрузки класса порядок выглядит следующим образом: Определения статических полей родительских классов. Инициализация статических полей и выполнение статических блоков родительских классов. Определения статических полей класса. Инициализация статических полей и выполнение статических блоков класса. Затем, при создании объекта, порядок выглядит следующим образом: Определения полей объекта из родительских классов. Инициализация полей и выполнение динамических блоков из родительских классов. Выполнение конструкторов из родительских классов. Определения полей объекта из его класса. Инициализация полей и выполнение динамических блоков из его класса. Выполнение конструктора из его класса. Когда существует цепочка предков, все действия выполняются сначала для самого дальнего предка (класс Object), а затем вниз по цепочке в том же порядке до текущего класса.

При наличии более чем одного типа в одном и том же разделе выше, действия выполняются в порядке появления в программе. Например, следующий код: public class T { static int i = 5; static { i = 10; } static { i = i * 3;

присваивает в каждом объекте переменной i значение 30. Но код: public class T { static { i = 10; } static int i = 5; static { i = i * 3;

присваивает значение 15. То есть, вначале создается поле, а потом все действия выполняются в порядке, указанном в программе — первый блок, затем инициализация поля, затем второй блок.

Возможные проблемы

Использование переменной до её определения Вопреки тому, что можно ожидать, следующий код: public class T { static { i = 5; i = i + 1; } static int i = 5; } не пройдёт компиляцию в строке 4 на том основании, что правая переменная i была использована, прежде чем она была определена, несмотря на то что строка 3 пройдёт компиляцию и выполнится без проблем, несмотря на то что левая i в строке 4 не вызывает ошибку, и несмотря на то что во время работы при достижении начала строки 4 переменная была определена и получила значение. Это происходит потому, что размещение переменных (например, в строке 3) проверяется по списку переменных, определённых на данный момент в процессе выполнения программы, включая все статические поля, а использование такой переменной проверяется по местоположению определения.

Локальная статическая переменная Вопреки тому, что можно ожидать, следующий код: public class T { static { int i = 10; } public static void main(String[] args) { System.out.println(i);

не пройдёт компиляцию в строке 6 на том основании, что переменная не определена, потому что определение переменной в статическом блоке не создает статическую переменную, а только локальную переменную в этом блоке. То есть код static {int i = 10;} не равнозначен коду static int i = 10;.

См. также Информатика Объектно-ориентированное программирование

Конструктор Финализатор Деструктор Конструктор копирования

Ссылки Initialization blocks, constructors and their order of execution, JavaGeek.com, 2013. Instance Initializer block in java, Tutorialspoint examples. Static Blocks in Java, JusForTechies.

Категория:Java (язык программирования) Категория:Программирование Категория:Объектно-ориентированное программирование