Enum is a very useful tool to represent a set of fixed content, and we can define and use it like a class which is much powerful and convenient.
But, when we were implementing some operations using the enum, I confronting some questions about some compiler errors.
So today, we will dive into how enum is implemented to understand the complaint issued by compiler.
Cannot find symbol
public enum EnumImpl {
A {
public static final int a = 1;
};
}
We confronting this error when we try to access A.a
outside enum constant A
. At first, it seems a little bit confusing, but after skimming the byte code, we can understand why:
public final static enum EnumImpl; A
final enum EnumImpl$1 extends EnumImpl {}
Translating it to Java code:
final enum EnumImpl$1 extends EnumImpl {...}
public final static EnumImpl A = new EnumImpl$1();
So, it become so obvious that we can’t access child’s element using father’s reference and that is where errors come.
Non-static variable cannot be referenced from a static context
public enum EnumImpl {
B {
public void c() {
System.out.println(s); // non-static variable s cannot be referenced from a static context
}
};
private int s;
}
Using similar translation, we get the following code:
final enum EnumImpl$2 extends EnumImpl {
public void c() {
System.out.println(s); //no error
}
}
public final static EnumImpl B = new EnumImpl$2();
But this code doesn’t have any error! Confused, we start searching.
Following the JLS of enum, we get the following line:
An enum declaration is implicitly final unless it contains at least one enum constant that has a class body (§8.9.1).
A nested enum type is implicitly static
Read to here, we guess that what we actually have (the anonymous synthetic class for B
) is a static class as following code snippet shows, which can’t access non-static variable.
static final enum EnumImpl$2 extends EnumImpl {
public void c() {
System.out.println(s); //no error
}
}
public final static EnumImpl B = new EnumImpl$2();
Illegal static declaration in inner class
But story still not finished yet. we change the test code as following, the compiler gives me some seems contradictory error messages.
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;
}
This two error prove the assumption of above translations are wrong! Didn’t have any thought about how this works, I asked ‘Nested enum is static?’ on StackOverflow.
Through many discussions, we get the following refs from JLS:
The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes;
An anonymous class declaration is automatically derived from a class instance creation expression by the Java compiler.
An anonymous class is never abstract (§8.1.1.1).
An anonymous class is always implicitly final (§8.1.1.2).
An anonymous class is always an inner class (§8.1.3); it is never static (§8.1.1, §8.5.1).
So the nested enum is indeed not static. But why the error message says it is a static context?
The only answers we can come up with is the following:
abstract class EnumImpl {
private int s;
static {
class Bclass extends EnumImpl {
public void method() {
System.out.println(s);// static context here
}
private static int b;// inner class here
}
}
}
Conclusion:
In this blog, we continue to doubt the conclusion we already get to make our understanding of enum deeper and deeper. We may still not get the final answer, but we get the point to approaching the right answer.
Ref
- Runnable code
- Answer for: Why can enum implementations not access private fields in the enum class
- Enum types in JLS
- Nested enum is static?
Written with StackEdit.
评论
发表评论