【问题标题】:Why is this enum code an illegal reference to a static field?为什么这个枚举代码是对静态字段的非法引用?
【发布时间】:2012-02-01 15:51:10
【问题描述】:

此代码无法编译,因为存在对静态字段的非法引用。

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 设为静态编译。

【问题讨论】:

    标签: java enums


    【解决方案1】:

    查看 Java 语言规范,第三版,第 8.9 节,http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9

    引用枚举类型的静态字段是编译时错误 这不是构造函数的编译时常量(第 15.28 节), 实例初始化程序块,或实例变量初始化程序 该类型的表达式。这是一个编译时错误 构造函数、实例初始化块或实例变量 枚举常量 e 的初始化表达式以引用自身或 在 e 的右侧声明的相同类型的枚举常量。

    讨论

    如果没有这条规则,显然合理的代码会在运行时失败 由于枚举类型固有的初始化循环性。 (一种 循环存在于任何具有“自类型”静态字段的类中。) 以下是可能会失败的代码示例:

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

    这个枚举类型的静态初始化会抛出一个 NullPointerException 因为静态变量 colorMap 是 枚举常量的构造函数运行时未初始化。这 上面的限制确保这样的代码不会编译。

    【讨论】:

      【解决方案2】:

      以大致等效、更简单的方式写出,更接近字节码,我们看到:

      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 实例变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-21
        相关资源
        最近更新 更多