Java枚举静态常量和实例变量

16

太好了!

这段代码一开始是可以工作的,但后来我决定添加一个默认颜色,结果它就停止工作了。我收到了以下错误:

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选择抛出一个错误。 有什么想法吗?


3
有必要拥有一个“defaultColor”字段吗?毕竟,你的代码不是应该只查看“Status.color”吗? - Brad Mace
4个回答

34

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);
}

12

首先必须初始化枚举常量。要进行初始化,必须调用构造函数。第一个构造函数引用了一个静态字段,在调用时这个静态字段不可能已经被初始化。


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);
    }
}

当然,在运行时会出现问题,但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),这种解决方法不适用,因为枚举类型中的静态字段不能在枚举本身之前移动(可能是纯语法原因)。为避免混淆,Java对枚举添加了额外的限制 - 构造函数中不能引用静态字段。
这个限制是不完全的。很难(如果不是不可能的话)检查构造函数中所有可能使用静态字段的情况。以下代码将编译,打破了这个限制:
enum Status
{
    OFF("Off");

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

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

0

你提供的错误链接是指访问枚举类的.class字面量,而不是引用枚举的实际静态字段。 - ColinD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接