阅读this question时,我打开编辑器尝试一些代码示例来验证和理解它。以下是我的代码:
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;
}
但是编译高级代码会让我更加困惑。
B
实际上属于静态类。所以在method
中,它是一个静态上下文。 嵌套枚举类型是隐式静态的。
以下是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
}
所以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;
}
}
}
答案 0 :(得分:4)
您对method()
的声明位置错误。你在常量体中声明它。但它不会覆盖任何东西。它属于枚举体,而不是实体。
实例子类型在枚举常量的静态初始化程序中声明。由于上下文是静态的,因此无法访问枚举实例变量。
您的枚举声明不是静态的,它是顶级的,顶级类不能是静态的。
常量体定义枚举的隐式嵌套匿名子类,并不构成JLS所指的嵌套枚举。每个常量都是您声明的枚举的不同匿名子类型,哪个子类型不是静态的。但是,子类型是在静态上下文中声明的,因此代码无法访问实例变量。
编辑:来自JLS的有用参考资料
https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.9.1 “枚举常量的可选类体隐式定义了一个匿名类声明(第15.9.5节),它扩展了直接封闭的枚举类型。类体由匿名类的通常规则控制;特别是它不能包含任何构造函数。只有当它们覆盖封闭枚举类型(第8.4.8节)中的可访问方法时,才可以在封闭枚举类型之外调用在这些类主体中声明的实例方法。“
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.9.5 “Java编译器会自动从类实例创建表达式派生出一个匿名类声明。匿名类永远不是抽象的(§8.1.1.1)。匿名类总是隐式最终的(§8.1.1.2)。匿名类是总是一个内部类(第8.1.3节);它永远不是静态的(§8.1.1,§8.5.1)。“
答案 1 :(得分:1)
错误消息“无法从静态上下文中引用非静态变量s”令人困惑,因为问题不是s
是静态的,而是不能在method
中访问。如果从private
中删除private int s;
,则错误消息消失。
要使method
声明有用,还需要在public void method() {}
声明之外添加public abstract void method();
或B
。
如果两者都做,则代码
enum EnumImpl {
B {
public void method() {
System.out.println(s);
}
};
public abstract void method();
int s;
}
将会编译,您可以调用EnumImpl.B.method()
。