Consider the following code:
class C {
final C C1 = new C() {
public void f() {
g();
}
};
private void g() {
}
}
enum E {
E1 {
public void f() {
g();
}
};
private void g() {
}
}
It struck me that the class and the enum are structurally very similar: the class has an inner class that references a private method; the enum has a value that references a private method.
But the big difference is: the enum won't compile. Unless I change the protection on g() to "protected" or less, it throws an error.
And the bizarre part is, the error is not "g has private access" or "cannot find symbol". No, it's "non-static method g() cannot be referenced from a static context"! WTF?
I solved the mystery by utter accident, when I changed the class to
class C {
static final C C1 = new C() {
...
That is, I made the variable referring to the instance of the inner class static. That made the class fail to compile with the same "static context" error I saw in the enum.
It took several minutes of open-mouth staring at the screen to get it: in the original class, the g() being called was not in the same object, but in the
outer object. Methods of object declared in a derived class cannot get to private members, even of the same object, declared in an ancestor class: that is the meaning of the word "private". But methods of an inner class can get to private members of the outer class. So in the original class, the inner-object could not see its own g(), so it looked at the outer-object's g(); when I changed the inner-object to static, there was no outer object, and I got an error to that effect.
Enum values are basically solitary instances of static inner classes of the class representing the enum itself and so, in the same situation produce the same error message.
Oddly, the following does compile:
enum E {
E1 {
public void f() {
E1.g();
}
};
private void g() {
}
}
That is, instead of accessing g() as E.this.g(), I accessed it statically as E.E1.g(). In fact, this was the first thing I tried -- under the wrong impression that f() was static within E1, not the E1 was static within E. In retrospect, I can see why it works, but I cannot explain it properly or defend it intellectually.
Who sez Java ain't fun?
M.