Почему этот код перечисления является незаконной ссылкой на статическое поле? - программирование
Подтвердить что ты не робот

Почему этот код перечисления является незаконной ссылкой на статическое поле?

Этот код не будет компилироваться, потому что существует недопустимая ссылка на статическое поле.

public enum Foo {

  A,
  B;

  private Foo[] foos = new Foo[] { Foo.A };

}

Нельзя ли получить доступ к статическим полям из инициализатора нестатического поля? Например:

public class Foo {

  static int A;

  private int[] foos = new int[] { Foo.A };

}

Это компилируется.

Обратите внимание, что в первом примере выполняется компиляция foos static.

4b9b3361

Ответ 1

Проверьте спецификацию языка Java, третье издание, раздел 8.9 на http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9

Это ошибка времени компиляции для ссылки на статическое поле типа перечисления это не константа времени компиляции (§15.28) от конструкторов, блоки инициализатора экземпляра, или инициализатор переменной экземпляра выражения этого типа. Это ошибка времени компиляции для конструкторы, блоки инициализатора экземпляра или переменная экземпляра выражения инициализатора константы enum en для ссылки на себя или на константу перечисления того же типа, которая объявляется справа от e.

Обсуждение

Без этого правила явно разумный код не будет работать во время выполнения из-за крутизны инициализации, присущей типам перечислений. (A круглость существует в любом классе с "самонастраиваемым" статическим полем.) Ниже приведен пример кода, который не срабатывает:

enum Color {
        RED, GREEN, BLUE;
        static final Map<String,Color> colorMap = 
        new HashMap<String,Color>();
        Color() {
            colorMap.put(toString(), this);
        }
    } 

Статическая инициализация этого типа перечисления вызовет NullPointerException, потому что статическая переменная colorMap неинициализируется, когда выполняются конструкторы для констант перечисления. ограничение выше гарантирует, что такой код не будет компилироваться.

Ответ 2

Написанный примерно эквивалентным, более простым способом, ближе к байтовому коду, мы видим:

public final class Foo {
    public static final Foo A = new Foo();
    public static final Foo B = new Foo();

    private Foo[] foos;

    private Foo() {
        this.foos = new Foo[] { Foo.A };
    }
}

Вы можете видеть, что для инициализации A мы вызываем конструктор, который читает A. Очевидно, что пока конструктор A не будет инициализирован.

(Как выясняется, этот более простой код компилируется. Он просто не делает того, чего вы можете ожидать.)

Вероятно, вы хотите Foo.values() вместо переменной экземпляра foos.