Почему этот код перечисления является недопустимой ссылкой на статическое поле? - PullRequest
17 голосов
/ 01 февраля 2012

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

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 в первом примере компилируется.

Ответы [ 2 ]

17 голосов
/ 01 февраля 2012

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

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

Обсуждение

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

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

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

7 голосов
/ 01 февраля 2012

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

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 переменной экземпляра.

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