Существуют ли какие-либо гарантии в JLS относительно порядка выполнения статических блоков инициализации?

Интересно, надежно ли использовать такую ​​конструкцию, как:

private static final Map<String, String> engMessages;
private static final Map<String, String> rusMessages;

static {
    engMessages = new HashMap<String, String> () {{
        put ("msgname", "value");
    }};
    rusMessages = new HashMap<String, String> () {{
        put ("msgname", "значение");
    }};
}

private static Map<String, String> msgSource;

static {
    msgSource = engMessages;
}

public static String msg (String msgName) {
    return msgSource.get (msgName);
}

Есть ли вероятность, что я получу NullPointerException, потому что блок инициализации msgSource будет выполняться перед блоком, который инициализирует engMessages?

(насчет того, почему я не делаю msgSource инициализацию в конце верхнего блока init.: просто дело вкуса; сделаю так, если описанная конструкция ненадежна)


person Roman    schedule 12.06.2010    source источник
comment
Я думаю, что есть гораздо лучшие способы интернационализации, чем этот. У меня нет опыта, чтобы рекомендовать, что это за способы, но я думаю, что это связано с выносом строк за пределы исходного кода (чтобы облегчить работу переводчикам-непрограммистам) и использованием различных механизмов уже разработан для интернационализации, в отличие от управления собственными картами, как это.   -  person polygenelubricants    schedule 12.06.2010
comment
@polygenelubricants: частично согласен. но у меня есть 3 причины: 1) это самый простой/быстрый способ для меня сейчас; 2) это не настоящая заявка, я делаю это как часть своей дипломной работы; 3) по-прежнему можно разобрать файлы свойств в статических инициализаторах, если это будет необходимо (но это не так).   -  person Roman    schedule 12.06.2010


Ответы (1)


Да, статические блоки инициализатора гарантированно выполняются в текстовом порядке.

Из JLS, раздел 12.4. .1:

Цель состоит в том, чтобы класс или тип интерфейса имел набор инициализаторов, переводящих его в согласованное состояние, и чтобы это состояние было первым состоянием, наблюдаемым другими классами. Статические инициализаторы и инициализаторы переменных класса выполняются в текстовом порядке и могут не ссылаться на переменные класса, объявленные в классе, объявления которого отображаются в текстовом виде после использования, даже если эти переменные класса находятся в области видимости (§8.3). .3). Это ограничение предназначено для обнаружения во время компиляции большинства циклических или иным образом искаженных инициализаций.

И из 12.4.2< /а>:

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

Лично я бы поместил все объявления переменных в начало, а затем один статический блок инициализатора. Я считаю, что это намного легче следовать.

person Jon Skeet    schedule 12.06.2010
comment
Предоставленная вами ссылка сейчас не работает. Может это быть приемлемым как правильный? Статические инициализаторы и инициализаторы переменных класса выполняются в текстовом порядке и могут не ссылаться на переменные класса, объявленные в классе, чьи объявления появляются в текстовом виде после использования, даже если эти переменные класса находятся в области видимости (§8.3.3). - person St.Antario; 28.09.2015
comment
@St.Antario: и в 12.4.1, и в 12.4.2 есть полезный текст. Вставлю обе ссылки. - person Jon Skeet; 28.09.2015