Статические конечные переменные экземпляра Java Enum
ура!
Этот код работал некоторое время, затем я решил добавить цвет по умолчанию, и он перестает работать. Я получаю следующую ошибку:
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 решила выбросить ошибку.
Любые мысли?
Ответы
Ответ 1
defaultColor
будет инициализироваться только после того, как конструкторы были вызваны, поэтому до этого времени оно будет иметь значение по умолчанию (null). Один из вариантов - поместить цвет по умолчанию в вложенный тип:
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);
}
Ответ 2
Сначала необходимо инициализировать константы перечисления. Чтобы инициализировать их, необходимо вызвать конструкторы. Первый конструктор ссылается на статическое поле, которое, возможно, не было инициализировано в момент его вызова.
Ответ 3
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 все равно. Задача программиста - упорядочить последовательности init, и компилятор не просто проверить все разбитые init-зависимости. В любом случае проблему легко исправить:
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());
}
Ответ 4
Обсуждение и Возможное обходное решение