Переменные статического экземпляра Java Enum - PullRequest
13 голосов
/ 22 июня 2011

Huzzah!

Этот код работал некоторое время, затем я решил добавить цвет по умолчанию, и он перестал работать.Я получаю следующую ошибку:

1 error found:
File: Status.java  [line: 20]
Error: Status.java:20: illegal reference to static field from initializer

Со следующим кодом во время компиляции.

import java.awt.Color;

enum Status
{
  OFF ("Off"),
  TRAINING ("Training", new Color(255, 191, 128)),
  BEGINNER ("Beginner", new Color(128, 255, 138)),
  INTERMEDIATE ("Intermediate", new Color(128, 212, 255)),
  ADVANCED ("Advanced", new Color(255, 128, 128));

  public final String name;
  public final Color color;

  public static final Color defaultColor = Color.WHITE;

  Status(String name)
  {
    this(name, defaultColor);
  }
  Status(String name, Color color)
  {
    this.name = name;
    this.color = color;
  }
}

Это должно работать, насколько я могу судить, но по какой-то причине Java решилавыбросить ошибку.Есть мысли?

Ответы [ 4 ]

27 голосов
/ 22 июня 2011

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

import java.awt.Color;

enum Status
{
  OFF ("Off"),
  TRAINING ("Training", new Color(255, 191, 128)),
  BEGINNER ("Beginner", new Color(128, 255, 138)),
  INTERMEDIATE ("Intermediate", new Color(128, 212, 255)),
  ADVANCED ("Advanced", new Color(255, 128, 128));

  public final String name;
  public final Color color;

  Status(String name)
  {
    this(name, Defaults.COLOR);
  }
  Status(String name, Color color)
  {
    this.name = name;
    this.color = color;
  }

  private static class Defaults
  {
     private static Color COLOR = Color.WHITE;
  }
}

Конечно, если вы ссылаетесь только на цвет по умолчанию один раз в коде, вы можете жестко закодировать его в вызове конструктора:

Status(String name)
{
  this(name, Color.WHITE);
}
12 голосов
/ 22 июня 2011

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

6 голосов
/ 22 июня 2011

Java позволяет это

class Status
{
    public static final Status OFF = new Status("Off");

    public static final Color defaultColor = Color.WHITE;

    Status(String name)
    {
      this(name, defaultColor);
    }
}

Конечно, у него будут проблемы во время выполнения, но Java это не волнует. Задача программиста - организовать последовательности инициализации, и компилятору непросто проверить все нарушенные зависимости инициализации. В любом случае проблему легко решить:

class Status
{
    // now it works, this field is initialized first
    public static final Color defaultColor = Color.WHITE;

    public static final Status OFF = new Status("Off");

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

Это ограничение наполовину. Нелегко (если не невозможно) проверить все возможные использования статических полей из конструктора. Следующий код будет компилироваться, преодолевая ограничение:

enum Status
{
    OFF("Off");

    public static final Color defaultColor = Color.WHITE;
    static Color defaultColor(){ return defaultColor; }

    Status(String name)
    {
      this(name, defaultColor());
    }
0 голосов
/ 22 июня 2011
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...