зачем нужны и какие бывают блоки инициализации
Блоки инициализации в Java
Что такое инициализация
Например, у нас есть переменная:
Мы получим ошибку «переменная не инициализирована»:
Привычные способы инициализации
или, например, в цикле:
Внутри класса, мы можем это делать так:
Инициализация с помощью блоков
Представим, что мы хотим задать базовые значения переменных. Можно сделать это так:
А можно использовать блок инициализации:
Выглядит лучше, правда? 🙂
Давайте посмотрим какие существуют блоки инициализации.
Виды блоков инициализации
Существует всего два типа блоков:
Как можно догадаться по названию:
Зачем используются блоки инициализации
Для того, чтобы Вы могли протестировать у себя на компьютере, возьмем такой код (все тот же класс Dog):
Теперь в нашем блоке инициализации есть только System.out.println(«Это нестатический блок инициализации!»). Запустим его со следующим main-ом:
И получим в консоли:
Как видите, работает. Если бы мы просто написали System.out.println, без блока инициализации, программа бы не запустилась:
Как видите, такое можно делать только внутри блока инициализации. Это особенно полезно если нам нужно производить какие-нибудь вычисления перед инициализацией переменных.
Подводим итог:
или для статического:
Блоки статической и объектной инициализации
Давайте начнем со следующего примера. Программа SmallSquares (маленькие квадраты) возвращает квадрат маленького целого числа. SmallSquares имеет 2 статические переменные и единственную открытую статическую функцию getSquare().
public class SmallSquares <
<>
private static final int LIMIT = 10 ;
private static final int [] square = new int [ LIMIT ] ;
public SmallSquares () < // не пишите такой код
for ( int i = 0 ; i ) <
square [ i ] = i * i;
>
>
>
public static int getSquare ( int i ) <
// Нет обработки ошибки, предположим, 0 return square [ i ] ;
>
public static void main ( String [] args ) <
new SmallSquares () ;
System.out.println ( «3 squared is » +
getSquare ( 3 )) ;
>
>
Откомпилируйте и запустите SmallSquares, вы должны получить следующий результат:
Как вы наверное догадались из комментария программы, это действительно плохой код. Мы игнорируем недостаток границ проверки аргумента getSquare(). Также игнорируем тот факт, что индексация в очереди чуть ли не дороже, чем простое возведение в квадрат числа. Отложим эти факты в сторону, сконцентрируемся на неэкономном создании объекта, называемом статическим методом.
А ещё лучше использовать статическую инициализацию. За словом статический (static) следует блок кода, окруженного фигурными скобками. Вы можете использовать статический блок для инициализации массива квадратов вот так:
Поставьте этот блок в код программы SmallSquare после объявления квадрата. Из-за статичности блок запрашивается единожды, когда создается класс. Теперь вам не нужен конструктор, и вы можете вызывать статическую функцию getSquare() без предшествующего создания класса. Вот улучшенный код:
public class SmallSquares <
<>
private static final int LIMIT = 10 ;
private static final int [] square = new int [ LIMIT ] ;
static <
for ( int i = 0 ; i ) <
square [ i ] = i * i;
>
>
public static int getSquare ( int i ) <
// Нет обработки ошибки, предположим,0 return square [ i ] ;
>
public static void main ( String [] args ) <
System.out.println ( «3 squared is » + getSquare ( 3 )) ;
>
>
Вы можете применять этот же метод к нестатическим кодам. Отметим, что данные инициализаторы вводились таким образом, что безымянным внутренним классам приписывалось определенное состояние. В следующем примере вы увидите, как использовать данные инициализаторы в контексте стандартных классов инициализации. Этот метод наиболее подходящий для безымянные классов.
public class ConstructorExample <
private final String userName;
private final static int [] square = new int [ 10 ] ;
public ConstructorExample () < // так не следует писать
this ( «Anonymous» ) ;
>
Откомпилируйте и запустите ConstructorExample. Вы должны получить следующий результат:
Пример конструктора можно привести в порядок, переместив поле инициализатора для имени пользователя (userName) и введя следующий блок инициализатора:
Данный блок инициализаторов выглядит как блок статического инициализатора без статического ключевого слова. Он запускается перед тем, как вызвать конструктор. Это значит, что вначале квадрат инициализируется не правильно в зависимости от того, вызывает ли пользователь конструктор без аргумента или использует сигнатуру, требующую строку (String). Отметить, что если у вас есть другой конструктор, который устанавливает размер массива, вы не сможете применять этот метод. Потому что данный инициализатор будет вызван, чтобы инициализировать квадрат, перед тем, как будет прочитан размер массива.
Вы можете разделить конструкторы в примере (ConstructorExample), передвинув следующие строки от конструктора без аргумента:
В следующей программе появляется пустой конструктор, ConstructorExample2 (пример конструктора 2), чтобы продемонстрировать введение данного блока инициализации.
public class ConstructorExample2 <
<>
private final String userName;
private static final int [] square = new int [ 10 ] ;
<
for ( int i = 0 ; i 10 ; i++ ) <
square [ i ] = i * i;
>
>
public ConstructorExample2 () <
userName = «Anonymous» ;
>
public void printSquare ( int i ) <
// Нет обработки ошибки, предположим,0 System.out.println ( «Hello » + userName ) ;
System.out.println ( i + » squared is » + square [ i ]) ;
>
В примере AnonymousExample используется функция createAnonSquare(). Эта функция создает безымянный внутренний класс, который распространяется на AnonymousSquare (безымянный квадрат). Этот пример не более чем инициализация переменных userName и Ed.
Безымянный класс наследует квадрат и функцию print(). Это значит, что вы можете создавать AnonymousSquare (Безымянный квадрат) и вызывать print(). Вы должны получить «Hi Ed, 3 squared is 9.» (Привет Эд, 3 в квадрате будет 9).
static class AnonymousSquare
private static final int [] square = new int [ 10 ] ;
<
for ( int i = 0 ; i 10 ; i++ )
square [ i ] = i * i;
>
String userName;
int i;
void print () <
System.out.println ( «Hi » + userName + «, » + i
+ » squared is » + square [ i ] + ‘.’
) ;
>
>
static AnonymousSquare createAnonSquare () <
return new AnonymousSquare () <
<
userName = «Ed» ;
i = 3 ;
>
> ;
>
Однажды, попробовав работать с блоками инициализации, вы возможно найдёте для них много приложений. Данные инициализаторы лучше всего подходят к безымянным внутренним классам и не часто используются в обычных Java-классах. Вы убедитесь, что статические инициализаторы очень удобные.
Что такое блок инициализации?
мы можем поместить код в конструктор или метод или блок инициализации. В чем польза блока инициализации? Необходимо ли, чтобы каждая программа java должна иметь его?
9 ответов
прежде всего, существует два типа инициализация блоков:
этот код должен иллюстрировать их использование и в каком порядке они выполняются:
блоки itialization экземпляра полезны, если вы хотите, чтобы некоторый код выполнялся независимо от того, конструктор используется или если вы хотите сделать некоторую инициализацию экземпляра для анонимных классов.
хотел бы добавить к ответу @aioobe
статические блоки инициализации супер классов
статические блоки инициализации класса
блоки инициализации экземпляра супер классов
конструкторы супер классы
блоки инициализации экземпляра класс!—1—>
несколько дополнительных пунктов, чтобы иметь в виду (пункт 1-повторение ответа @aioobe):
код в блоке статической инициализации будет выполняться во время загрузки класса (и да, это означает только один раз на загрузку класса), перед созданием любых экземпляров класса и перед вызовом любых статических методов.
экземпляр блок инициализации фактически копируется компилятором Java в каждый конструктор класса. Поэтому каждый раз, когда выполняется код в блоке инициализации экземпляра ровно перед кодом в конструкторе.
хороший ответ от aioobe добавление еще нескольких очков
это похоже на утверждение очевидного, но кажется немного более ясным.
пример кода, который утвержден в качестве ответа здесь, является правильным, но я не согласен с ним. Он не показывает, что происходит, и я покажу вам хороший пример, чтобы понять, как на самом деле работает JVM:
прежде чем начать комментировать исходный код, я дам вам краткое объяснение статические переменные класса:
теперь давайте посмотрим на этот код:
существует полиморфное создание объекта, но прежде чем войти в класс B и его основной метод, JVM инициализирует все переменные класса(статические), затем проходит через статические блоки инициализации, если они существуют, а затем входит в класс B и начинается с выполнения основного метода. Он переходит к конструктору класса B, затем немедленно (неявно) вызывает конструктор класса A, используя полиморфизм метод(переопределенный метод), вызываемый в теле конструктора класса A, является тем, который определен в классе B, и в этом случае переменная с именем instanceVariable используется перед повторная инициализация. После закрытия конструктора класса B поток возвращается конструктору класса B, но сначала он переходит в нестатический блок инициализации перед печатью «конструктор». Для лучшего понимания отладки с помощью некоторой IDE я предпочитаю Eclipse.
инициализатор блок содержит код, который всегда выполняется при создании экземпляра. Он используется для объявления / инициализации общей части различных конструкторов класса.
порядок конструкторов инициализации и блока инициализатора не имеет значения, блок инициализатора всегда выполняется перед конструктором.
Что делать, если мы хотим выполнить некоторый код один раз для всех объектов класса?
мы используем статический блок в Java.
блоки инициализации выполняются при инициализации класса и до вызова конструкторов. Обычно они размещаются над конструкторами в фигурных скобках. Нет никакой необходимости включать их в свои занятия.
Они обычно используются для инициализации переменных ссылочного. Это страница дает хорошее объяснение
вопрос не совсем ясен, но вот краткое описание способов инициализации данных в объекте. Предположим, у вас есть класс, который содержит список объектов.
1) Поместите начальные значения в объявление поля:
2) назначить начальные значения в конструкторе:
они оба предполагают, что вы не хотите передавать «данные» в качестве аргумента конструктора.
вещи становятся немного сложнее, если вы смешиваете перегруженные конструкторы с внутренними данными, как указано выше. Подумайте:
обратите внимание, что существует много повторяющегося кода. Вы можете исправить это, заставив конструкторы вызывать друг друга, или у вас может быть частный метод инициализации, который каждый конструктор вызывает:
два (более или менее) эквивалентны.
Я надеюсь, что дает вам некоторые подсказки о том, как инициализировать данные в объекты. Я не буду говорить о статических блоках инициализации поскольку это, вероятно, немного продвинуто на данный момент.
EDIT: я интерпретировал ваш вопрос как «как инициализировать переменные экземпляра», а не «как работают блоки инициализатора», поскольку блоки инициализатора являются относительно продвинутой концепцией, и из тона вопроса кажется, что вы спрашиваете о более простой концепции. Я могу ошибаться.
Что такое блок инициализации?
Мы можем поместить код в конструктор или метод или блок инициализации. Каково использование блока инициализации? Нужно ли, чтобы каждая программа Java имела это?
ОТВЕТЫ
Ответ 1
Прежде всего, существуют два типа блоков инициализации:
Этот код должен иллюстрировать их использование и в каком порядке они выполняются:
Блоки itialization экземпляра полезны, если вы хотите, чтобы какой-то код запускался независимо от того, какой конструктор используется или если вы хотите выполнить некоторую инициализацию экземпляра для анонимных классов.
Ответ 2
хотел бы добавить к ответу @aioobe
статические блоки инициализации суперклассов
статические блоки инициализации класса
блоки инициализации экземпляров суперклассов
конструкторы суперклассов
блоки инициализации экземпляра класса
Код в статическом блоке инициализации будет выполняться во время загрузки класса (и да, это означает только один раз на загрузку класса), прежде чем будут созданы какие-либо экземпляры класса и до вызова каких-либо статических методов.
Блок инициализации экземпляра фактически копируется компилятором Java в каждый конструктор класса. Поэтому каждый раз, когда блок инициализации кода в экземпляре выполняется точно до кода в конструкторе.
Ответ 3
хороший ответ by aioobe добавив еще несколько очков
похожее на очевидное, но кажется немного более понятным.
Ответ 4
Пример кода, который одобрен в качестве ответа здесь, является правильным, но я не согласен с ним. Он не показывает, что происходит, и я покажу вам хороший пример, чтобы понять, как работает JVM:
Прежде чем начинать комментировать исходный код, я дам вам краткое описание статических переменных класса:
Теперь посмотрим на код выше:
Существует полиморфное создание объекта, но прежде чем вводить класс 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) Поместите начальные значения в объявление поля:
2) Назначьте начальные значения в конструкторе:
В обоих случаях предполагается, что вы не хотите передавать «данные» в качестве аргумента конструктора.
Все становится немного сложнее, если вы смешиваете перегруженные конструкторы с внутренними данными, как указано выше. Рассмотрим:
Обратите внимание, что много повторяющегося кода. Вы можете исправить это, заставив конструкторы вызвать друг друга, или вы можете получить частный метод инициализации, который вызывает каждый конструктор:
Эти два (более или менее) эквивалентны.
Надеюсь, это даст вам несколько советов о том, как инициализировать данные в ваших объектах. Я не буду говорить о статических инициализационных блоках, которые, вероятно, немного продвинулись на данный момент.
EDIT: я интерпретировал ваш вопрос как «как инициализировать мои переменные экземпляра», а не «как работают блоки инициализатора» в качестве блоков инициализации, является относительно продвинутой концепцией, и из тонов вопроса кажется, спрашивая о более простой концепции. Я мог ошибаться.
Ответ 9
Ответ 10
Блок инициализатора определен внутри класса, а не как часть метода. Он выполняется для каждого объекта, созданного для класса. В следующем примере класс Employee определяет блок инициализатора:
Ответ 11
Инициализм Отображает текст внутри элемента шрифтом немного меньшего размера.
Руководство по созданию объектов в Java
Взгляните на различные способы инициализации примитивов и объектов в Java.
1. Обзор
Проще говоря, прежде чем мы сможем работать с объектом в JVM, он должен быть инициализирован.
В следующих разделах мы рассмотрим различные способы инициализации примитивных типов и объектов.
2. Декларация против Инициализация
Давайте начнем с того, что убедимся, что мы на одной странице.
Объявление-это процесс определения переменной вместе с ее типом и именем.
Здесь мы объявляем переменную id :
Инициализация, с другой стороны, заключается в присвоении значения; например:
Чтобы продемонстрировать это, мы создадим класс User с именем и id свойствами:
Далее мы увидим, что инициализация работает по-разному в зависимости от типа поля, которое мы инициализируем.
3. Объекты против примитивов
Java предоставляет два типа представления данных: примитивные типы и ссылочные типы. В этом разделе мы обсудим различия между ними в отношении инициализации.
Java имеет восемь встроенных типов данных, называемых примитивными типами Java; переменные этого типа содержат свои значения напрямую.
Ссылочные типы содержат ссылки на объекты (экземпляры классов). В отличие от примитивных типов, которые хранят свои значения в памяти, где выделена переменная, ссылки не содержат значения объекта, на который они ссылаются.
Вместо этого ссылка указывает на объект, сохраняя адрес памяти, в котором находится объект.
Обратите внимание, что Java не позволяет нам узнать, что такое адрес физической памяти. Скорее, мы можем использовать ссылку только для ссылки на объект.
Давайте рассмотрим пример, который объявляет и инициализирует ссылочный тип из нашего класса User :
Давайте продолжим изучать больше о создании объектов.
5. Создание объектов
Давайте обсудим конструкторы и ключевое слово new более подробно.
Ключевое слово new отвечает за выделение памяти для нового объекта с помощью конструктора.
Если мы не предоставим конструктор явно, компилятор создаст конструктор по умолчанию, который не имеет аргументов и просто выделяет память для объекта.
Давайте добавим конструктор в наш класс User :
Теперь мы можем использовать наш конструктор для создания объекта User с начальными значениями его свойств:
6. Переменная Область действия
В следующих разделах мы рассмотрим различные типы областей, в которых может существовать переменная в Java, и как это влияет на процесс инициализации.
6.1. Переменные экземпляра и класса
Переменные экземпляра и класса не требуют от нас их инициализации. Как только мы объявляем эти переменные, им присваивается значение по умолчанию следующим образом:
Теперь давайте попробуем определить некоторые переменные, связанные с экземплярами и классами, и проверить, имеют ли они значение по умолчанию или нет:
6.2. Локальные переменные
Например, следующий код генерирует ошибку компилятора:
7. Последнее Ключевое Слово
Давайте добавим константу в наш класс User :
Константы должны быть инициализированы либо при их объявлении, либо в конструкторе.
8. Инициализаторы в Java
В Java инициализатор – это блок кода, который не имеет связанного имени или типа данных и помещается вне любого метода, конструктора или другого блока кода.
Java предлагает два типа инициализаторов: статические и инициализаторы экземпляров. Давайте посмотрим, как мы можем использовать каждый из них.
8.1. Инициализаторы экземпляров
Мы можем использовать их для инициализации переменных экземпляра.
Чтобы продемонстрировать, давайте предоставим значение для пользователя id с помощью инициализатора экземпляра в нашем классе User :
8.2. Блок Статической Инициализации
Статический инициализатор или статический блок – это блок кода, который используется для инициализации статических полей. Другими словами, это простой инициализатор, отмеченный ключевым словом static:
9. Порядок инициализации
При написании кода, который инициализирует различные типы полей, конечно, мы должны следить за порядком инициализации.
В Java порядок операторов инициализации выглядит следующим образом:
10. Жизненный цикл объекта
Теперь, когда мы научились объявлять и инициализировать объекты, давайте выясним, что происходит с объектами, когда они не используются.
В отличие от других языков, где нам приходится беспокоиться об уничтожении объектов, Java заботится об устаревших объектах через свой сборщик мусора.
С другой стороны, сборщик мусора – это программа Java, которая заботится об автоматическом управлении памятью путем удаления объектов, которые больше недоступны.
Чтобы объект Java стал недоступным, он должен столкнуться с одной из следующих ситуаций:
В заключение, объект сначала создается из класса, обычно используя ключевое слово new. Тогда объект живет своей жизнью и предоставляет нам доступ к своим методам и полям.
Наконец, когда он больше не нужен, сборщик мусора уничтожает его.
11. Другие методы создания объектов
Отражение-это механизм, который мы можем использовать для проверки классов, полей и методов во время выполнения. Вот пример создания нашего Пользователя объекта с помощью отражения:
Следующий метод, клонирование, – это способ создания точной копии объекта. Для этого наш класс User должен реализовать интерфейс Cloneable :
Теперь мы можем использовать метод clone() для создания нового клонированного пользователя объекта, который имеет те же значения свойств, что и объект user :
Мы также можем использовать Мы также можем использовать класс для выделения памяти для объекта без вызова конструктора:
12. Заключение
В этом уроке мы рассмотрели инициализацию полей в Java. Мы обнаружили различные типы данных в Java и способы их использования. Мы также подробно рассмотрели несколько способов создания объектов в Java.