嵌套枚举是静态的?

Ton*_*ony 6 java enums

在阅读这个问题时,我打开我的编辑器尝试一些代码示例来验证和理解它。以下是我的代码:

public enum EnumImpl {

    B {
        public void method() {
            System.out.println(s); //(1)non-static variable s cannot be referenced from a static context
        }
        public static int b;  //(2)Illegal static declaration in inner class
    };

    private int s;
}
Run Code Online (Sandbox Code Playgroud)

但是编译上面的代码让我更加困惑。

  • 第一个错误来自上面的问题表明B实际上属于静态类。所以在 中method,它是一个静态上下文。
  • 相比之下,第二个错误说这是一个内部类——java doc所说的非静态嵌套类。
  • 以下是我从JLS引用的一行,但似乎有点混乱和模糊。

    嵌套的枚举类型是隐式静态的。

  • 以下是B的匿名合成类的字节码:

    final class enum_type.EnumImpl$1 extends enum_type.EnumImpl {
      enum_type.EnumImpl$1(java.lang.String, int);
        Code:
          0: aload_0
          1: aload_1
          2: iload_2
          3: aconst_null
          4: invokespecial #1                  // Method enum_type/EnumImpl."<init>":(Ljava/lang/String;ILenum_type/EnumImpl$1;)V
          7: return
    
      public void method();
        Code:
          0: return
    }
    
    Run Code Online (Sandbox Code Playgroud)

那么 B 的类是否是静态的?

@Lew Bloch 似乎在说它如下(行为与上面的枚举示例匹配,但如果这是真的,则链接问题的答案在某些意义上是错误的)。

abstract class Cmp {    
    private int s;
    static {
        class Bclass extends Cmp {
            public void method() {
//                System.out.println(s);
            }
//            private static int b;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Lew*_*och 4

您的声明method()位置错误。您在常量主体中声明它。但它不会覆盖任何东西。它属于枚举体,而不是实例体。

\n\n

实例子类型在枚举常量的静态初始值设定项中声明。由于上下文是静态的,因此它无法访问枚举实例变量。

\n\n

您的枚举声明不是静态的,它是顶级的,并且顶级类不能是静态的。

\n\n

常量体定义了枚举的隐式嵌套匿名子类,并且不构成 JLS 所指的嵌套枚举。每个常量都是您所声明的枚举的不同匿名子类型,该子类型不是静态的。但是,子类型是在静态上下文中声明的,因此这就是代码无法访问实例变量的原因。

\n\n

编辑:来自 JLS 的有用参考

\n\n

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.9.1 \n“枚举常量的可选类主体隐式定义了一个匿名类声明(\ xc2\xa715.9.5) 扩展了直接封闭的枚举类型。类主体受匿名类的通常规则管辖;特别是它不能包含任何构造函数。在这些类主体中声明的实例方法可以在封闭枚举类型之外调用仅当它们覆盖封闭枚举类型 (\xc2\xa78.4.8) 中的可访问方法时。”

\n\n

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.9.5 \n“匿名类声明是由Java自动从类实例创建表达式派生的编译器。匿名类永远不是抽象的 (\xc2\xa78.1.1.1)。匿名类始终是隐式最终的 (\xc2\xa78.1.1.2)。匿名类始终是内部类 (\xc2\xa78 .1.3);它永远不是静态的(\xc2\xa78.1.1, \xc2\xa78.5.1)。”

\n

  • 问题基本上是问枚举常量“B”是否是静态的。OP 收到关于此主题的两条相互矛盾的错误消息。不幸的是,您的回答没有解决这个问题。 (2认同)