Почему инициализация констант перечисления Java не завершена? - PullRequest
9 голосов
/ 25 августа 2011

Я наткнулся на очень странную ошибку и не могу объяснить, почему это происходит. Представьте себе следующее перечисление:

import java.awt.Color;

public class test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(MyEnum.CONSTANT1.get());
        System.out.println(MyEnum.CONSTANT2.get());
    }

    private enum MyEnum {
        CONSTANT1(staticMethod1()),
        CONSTANT2(staticMethod2());

        private static final Color WHY_AM_I_NULL = new Color(255, 255, 255);

        private final Color color;

        private MyEnum(Color color) {
            this.color = color;
        }

        public Color get() {
            return color;
        }

        private static Color staticMethod1() {
            return new Color(100, 100, 100);
        }

        private static Color staticMethod2() {
            return WHY_AM_I_NULL;
        }
    }

}

Результаты при запуске:

java.awt.Color[r=100,g=100,b=100]
null

Вопрос в том, почему второй является нулевым?

Ammendment: Если вы поместите WHY_AM_I_NULL в закрытый статический класс внутри перечисления, то он инициализируется первым.

Ответы [ 4 ]

13 голосов
/ 25 августа 2011

Проблема в том, что все статические поля (и количество перечислений как таковые) инициализируются в объявленном порядке ( спецификация ). Поэтому, когда создается экземпляр CONSTANT2, поле WHY_AM_I_NULL все еще не инициализировано (и, следовательно, null).

Поскольку вы не можете поместить поле перед экземплярами enum, вам нужно найти какой-то другой способ сделать то, что вы хотите (например, поместить поле вне класса enum). Если вы скажете нам, чего вы действительно хотите достичь, вы можете внести дополнительные предложения.

Редактировать: Если вы поместите WHY_AM_I_NULL во вложенный класс, поля этого класса будут инициализированы при первом обращении к классу (т. Е. В этом случае во время выполнения staticMethod2).

4 голосов
/ 25 августа 2011

Перечисления являются функцией компилятора.Фактически компилятор создает класс с именем MyEnum, который содержит 2 открытых статических поля CONSTANT1 и CONSTANT2 и другой код.

Статическая инициализация выполняется сверху вниз, поэтому CONSTANT2 создается и инициализируется перед статической переменной WHY_AM_I_NULL.Вот почему WHY_AM_I_NULL является нулевым при инициализации CONSTANT2.

2 голосов
/ 25 августа 2011

WHY_AM_I_NULL равно нулю, когда staticMethod2 вызывается - так JLS определяет инициализацию

В другой последовательности вы получите 100, 255 вместо 100, null:

private static final Color WHY_AM_I_NULL = new Color(255, 255, 255);
private enum MyEnum {
    CONSTANT1(staticMethod1()),
    CONSTANT2(staticMethod2());
    //...
1 голос
/ 25 августа 2011

Это потому, что статические поля (включая значения перечисления) инициализируются в порядке их появления в файле.

Итак CONSTANT1 и CONSTANT2 инициализируются до WHY_AM_I_NULL, поэтому CONSTANT2 инициализируется с null.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...