Статический блок инициализации работает не так, как ожидалось

#java #static-initializer

Вопрос:

У меня есть два класса, «Test1» и «Test0», как показано в этом коде.

 public class Test1 {
    public static void main(String...args) {
        System.out.print(Test0.randomName);
    }
}
public class Test0 {
    public static String randomName = initRandomName();
    private static String string0;
    
    static {
        string0 = "George";
    }
    private static String initRandomName() {
        return "Mr. " string0;
    }
}
 

Я думал, что там будет напечатан мистер Джордж, но там был напечатан мистер Нуль.
И я не понимаю, что происходит. Пожалуйста, помогите мне. Спасибо.

Комментарии:

1. Перемещение назначения string0 перед инициализацией randomName должно исправить это. Статическая переменная может иметь нулевые значения, и randomName доступ к string0 ней осуществляется еще до того, как ей будет присвоено значение.

Ответ №1:

JLS 12.4.2 подробно описывает процедуру инициализации. В частности:

Затем выполните инициализаторы переменных класса и статические инициализаторы класса или инициализаторы полей интерфейса в текстовом порядке, как если бы они были одним блоком.

Другими словами, вы можете представить, что ваш Test0 класс написан так:

 public class Test0 {
    public static String randomName;
    private static String string0;
    
    static {
        randomName = initRandomName();
        string0 = "George";
    }

    private static String initRandomName() {
        return "Mr. "   string0;
    }
}
 

Поэтому, когда initRandomName() выполняется, string0 по-прежнему равно нулю.

Вы можете переместить инициализацию randomName поля в положение после статического инициализатора, например так:

 class Test0 {
    private static String string0;

    static {
        string0 = "George";
    }

    public static String randomName = initRandomName();

    private static String initRandomName() {
        return "Mr. " string0;
    }
}
 

… но это довольно хрупко, полагаться на то, что никто не переупорядочивает членов класса, не понимая последствий.

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

Комментарии:

1. Спасибо. Ваш ответ действительно полезен. Я хотел знать, как работает статическая инициализация, и теперь я ее понял.