Java Enum静态最终实例变量

ske*_*gse 15 java enums static final compiler-errors

好哇!

这段代码工作了一段时间,然后我决定添加一个默认颜色,它停止工作.我收到以下错误:

1 error found:
File: Status.java  [line: 20]
Error: Status.java:20: illegal reference to static field from initializer
Run Code Online (Sandbox Code Playgroud)

在编译时使用以下代码.

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这应该可以工作,但无论出于什么原因,Java决定抛出一个错误.有什么想法吗?

Jon*_*eet 29

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,如果您只在代码中引用一次默认颜色,那么您也可以在构造函数调用中对其进行硬编码:

Status(String name)
{
  this(name, Color.WHITE);
}
Run Code Online (Sandbox Code Playgroud)


Col*_*inD 12

必须首先初始化枚举常量.要初始化它们,必须调用构造函数.第一个构造函数引用一个静态字段,该字段在调用时可能无法初始化.


irr*_*ble 6

Java允许这样做

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

    public static final Color defaultColor = Color.WHITE;

    Status(String name)
    {
      this(name, defaultColor);
    }
}
Run Code Online (Sandbox Code Playgroud)

当然它在运行时会有问题,但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");
Run Code Online (Sandbox Code Playgroud)

但是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());
    }
Run Code Online (Sandbox Code Playgroud)