9 ответов:
во-первых, есть два типа инициализация блоков:
- инициализации экземпляра блока и
- статические блоки инициализации.
этот код должен иллюстрировать их использование и в каком порядке они выполняются:
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 экземпляра полезны, если вы хотите, чтобы какой-то код выполнялся независимо от того, какой конструктор используется или если вы хотите сделать некоторую инициализацию экземпляра для анонимных классов.
хотел бы добавить к ответу @aioobe
порядок выполнения:
статические блоки инициализации суперклассов
статические блоки инициализации класса
блоки инициализации экземпляров суперклассов
конструкторы суперклассов
блоки инициализации экземпляра класс
конструктор класса.
несколько дополнительных пунктов, чтобы иметь в виду (пункт 1-это повторение ответа @aioobe):
код в блоке статической инициализации будет выполняться во время загрузки класса (и да, это означает только один раз на загрузку класса), прежде чем будут созданы какие-либо экземпляры класса и перед вызовом каких-либо статических методов.
экземпляр блок инициализации фактически копируется компилятором Java в каждый конструктор, который имеет класс. Поэтому каждый раз, когда код в блоке инициализации экземпляра выполняется ровно перед кодом в конструкторе.
хороший ответ от 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это похоже на констатацию очевидного, но кажется немного более ясным.
пример кода, который утвержден в качестве ответа здесь правильный, но я не согласен с ним. Это не показывает, что происходит, и я собираюсь показать вам хороший пример, чтобы понять, как на самом деле работает 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"); } }прежде чем начать комментировать исходный код, я дам вам краткое объяснение статические переменные класса:
во-первых, они называются переменными класса, они принадлежат классу, а не конкретному экземпляру класса. Все экземпляры класса совместно используют эту статическую переменную (class). Каждая переменная имеет значение по умолчанию, в зависимости от типа примитива или ссылки. Другое дело, когда вы переназначаете статическую переменную в некоторых членах класса (блоки инициализации, конструкторы, методы, свойства) и при этом вы изменяете значение статической переменной не для конкретного экземпляра, а для всех экземпляров. В заключение статической части я скажу, что статические переменные класса создаются не при первом создании экземпляра класса, они создаются при определении класса, они существуют в JVM без необходимости каких-либо экземпляров. Поэтому правильный доступ статических членов из внешнего класса (класс, в котором они не определены) заключается в использовании имени класса, следующего за точкой, а затем статического члена, к которому вы хотите получить доступ (шаблон:
<CLASS_NAME>.<STATIC_VARIABLE_NAME>).теперь давайте посмотрим на этот код:
точка входа является основным методом - есть всего три строки кода. Я хочу сослаться на пример, который в настоящее время утвержден. Согласно ему первое, что должно быть напечатано после печати "статического блока инициализации",-это "блок инициализации", и вот мое несогласие, нестатический блок инициализации не вызывается перед конструктором, он вызывается перед любыми инициализациями конструкторов класса, в котором определен блок инициализации. Конструктор класса-это первое, что участвует при создайте объект (экземпляр класса), а затем при вводе конструктора первая вызываемая часть является либо неявным (по умолчанию) супер конструктором, либо явным супер конструктором, либо явным вызовом другого перегруженного конструктора (но в какой-то момент, если есть цепочка перегруженных конструкторов, последний вызывает супер конструктор, неявно или явно).
существует полиморфное создание объекта, но прежде чем войти в класс B и его основной метод, JVM инициализирует все переменные класса(статические), затем проходит через статические блоки инициализации, если таковые существуют, а затем входит в класс B и начинается с выполнения основного метода. Он переходит к конструктору класса B, а затем немедленно (неявно) вызывает конструктор класса A, используя полиморфизм метод (переопределенный метод), вызываемый в теле конструктора класса A, является тем, который определен в классе B, и в этом случае переменная с именем instanceVariable используется до повторная инициализация. После закрытия конструктора класса B поток возвращается в конструктор класса B, но сначала он переходит в нестатический блок инициализации перед печатью "конструктор". Для лучшего понимания отлаживайте его с помощью некоторой IDE, я предпочитаю Eclipse.
инициализатор блок содержит код, который всегда выполняется при создании экземпляра. Он используется для объявления / инициализации общей части различных конструкторов класса.
порядок инициализации конструкторов и блока инициализатора не имеет значения, блок инициализатора всегда выполняется перед конструктором.
Что делать, если мы хотим выполнить некоторый код один раз для всех объектов класса?
мы используем статический блок в Java.
блоки инициализации выполняются всякий раз, когда класс инициализируется и перед вызовом конструкторов. Они обычно размещаются над конструкторами в фигурных скобках. Это не обязательно включать их в свои занятия.
Они обычно используются для инициализации переменных ссылочного. Это страница дает хорошее объяснение
вопрос не совсем ясен, но вот краткое описание способов инициализации данных в объекте. Предположим, у вас есть класс, который содержит список объектов.
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: я интерпретировал ваш вопрос как "как инициализировать мои переменные экземпляра", а не "как работают блоки инициализатора", поскольку блоки инициализатора являются относительно продвинутой концепцией, и из тона вопроса кажется, что вы спрашиваете о более простой концепции. Я могу ошибаться.
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
блок инициализатора определен внутри класса, а не как часть метода. Он выполняется для каждого объекта, созданного для класса. В следующем примере класс
Employeeопределяет блок инициализатора:class Employee { { System.out.println("Employee:initializer"); } }
Comments