Создание объекта с использованием статического ключевого слова в Java
class abc {
int a = 0;
static int b;
static abc h = new abc(); //line 4
public abc() {
System.out.println("cons");
}
{
System.out.println("ini");
}
static {
System.out.println("stat");
}
}
public class ques {
public static void main(String[] args) {
System.out.println(new abc().a);
}
}
Когда я написал этот код, я получаю вывод в следующем порядке:
ini
cons
stat
ini
cons
0
Здесь, когда я создал новый объект в main(), class abc
, был загружен, а переменные static
и блоки выполняются в порядке их написания. Когда управление переходит к строке 4 static abc h = new abc();
Вызывается блок инициализации экземпляра. Зачем? почему статический блок не вызывается, когда новый объект создается в строке 4, и до этого времени статический блок также не вызывался даже один раз, поэтому в соответствии с соглашением должен был быть вызван статический блок. Почему этот неожиданный выход идет?
Ответы
Ответ 1
Инициализация статических полей и статические блоки выполняются в том порядке, в котором они объявлены. В вашем случае код эквивалентен этому после разделения объявления и инициализации:
class abc{
int a;
static int b;
static abc h;//line 4
static {
h = new abc();//line 4 (split)
System.out.println("stat");
}
public abc() {
a = 0;
System.out.println("ini");
System.out.println("cons");
}
}
public class ques{
public static void main(String[] args) {
System.out.println(new abc().a);
}
}
Итак, когда вы достигаете строки 4 из вашего кода, статическая инициализация фактически выполняется и еще не закончена. Следовательно, ваш конструктор вызывается до того, как stat
может быть напечатан.
Ответ 2
JLS говорит:
Выполняются статические инициализаторы и инициализаторы переменных класса в текстовом порядке и не может ссылаться на переменные класса, объявленные в класс, чьи объявления появляются после использования, хотя даже эти переменные класса входят в сферу действия (§8.3.2.3). Это ограничение предназначенный для обнаружения во время компиляции большинства круговых или иных неправильные инициализации.
Это именно ваш случай.
Вот ваш оригинальный пример: http://ideone.com/pIevbX - статический инициализатор abc
идет после назначения статического экземпляра abc
- так статический инициализатор не может быть выполнен - он текстовый после инициализации статической переменной
Переместить строку 4 после статического блока инициализации - http://ideone.com/Em7nC1:
class abc{
int a = 0;
static int b;
public abc() {
System.out.println("cons");
}
{
System.out.println("ini");
}
static {
System.out.println("stat");
}
static abc h = new abc();//former line 4
}
Теперь вы можете увидеть следующий вывод:
stat
ini
cons
ini
cons
0
Теперь порядок инициализации больше похож на ожидаемый - сначала называется статический инициализатор, а затем статический экземпляр abc
инициализируется обычным образом.