I have a enum type class:
public enum Operation { PLUS() { @Override double apply(double x, double y) { // ERROR: Cannot make a static reference // to the non-static method printMe()... printMe(x); return x + y; } }; private void printMe(double val) { System.out.println("val = " + val); } abstract double apply(double x, double y); }
As you see above, I have defined one enum
type which has value PLUS
. It contains a constant-specific body. In its body, I tried to call printMe(val);
, but I got the compilation error:
Cannot make a static reference to the non-static method printMe().
Why do I get this error? I mean I am overriding an abstract method in PLUS
body. Why is it in static
scope? How to get rid of it?
I know adding a static
keyword on printMe(){...}
solves the problem, but I am interested to know if there is another way if I want to keep printMe()
non-static?
Another issue, quite similar as above one, but this time the error message sounds the other way around, i.e. PLUS(){...}
has non-static context:
public enum Operation { PLUS() { // ERROR: the field "name" can not be declared static // in a non-static inner type. protected static String name = "someone"; @Override double apply(double x, double y) { return x + y; } }; abstract double apply(double x, double y); }
I try to declare a PLUS
-specific static
variable, but I end up with error:
the field "name" can not be declared static in a non-static inner type.
Why can I not define static constant inside PLUS
if PLUS
is an anonymous class? The two error messages sound contradictory to each other, as the 1st error message says PLUS(){...}
has static context while the 2nd error message says PLUS(){...}
has non-static context. I am even more confused now.
The only difference is that enum constants are public , static and final (unchangeable - cannot be overridden). An enum cannot be used to create objects, and it cannot extend other classes (but it can implement interfaces).
All Enums are implicitly static, its just you don't need to write the static keyword.
Enums are lists of constants. When you need a predefined list of values which do represent some kind of numeric or textual data, you should use an enum. You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values.
Yes, enums are effectively static.
Well this is a strange case.
It appears that the problem is:
In this case, the private member should be accessible (6.6.1.):
Otherwise, the member or constructor is declared
private
, and access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member or constructor.
However, private members are not inherited (8.2):
Members of a class that are declared
private
are not inherited by subclasses of that class.
Therefore, printMe
is not a member of the anonymous subclass and the compiler searches for it within the superclass* Operation
(15.12.1):
If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T.
This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy.
And here is where it gets strange. Because printMe
is found in a class that also encloses PLUS
, the object that the method is called on is instead determined to be an enclosing instance of Operation
, which doesn't exist (15.12.4.1):
Otherwise, let T be the enclosing type declaration of which the method is a member, and let n be an integer such that T is the n'th lexically enclosing type declaration of the class whose declaration immediately contains the method invocation. The target reference is the n'th lexically enclosing instance of
this
.It is a compile-time error if the n'th lexically enclosing instance of
this
does not exist.
So in short, because printMe
is only a member of Operation
(and not inherited), the compiler is compelled to invoke printMe
on a non-existent outer instance.
However, the method is still accessible and we can find it by qualifying the invocation:
@Override double apply(double x, double y) { // now the superclass is searched // but the target reference is definitely 'this' // vvvvvv super.printMe(x); return x + y; }
The two error messages sound contradictory to each other [...].
Yes, this is a confusing aspect of the language. On the one hand, an anonymous class is never static (15.9.5), on the other hand, an anonymous class expression can appear in a static context and therefore has no enclosing instance (8.1.3).
An anonymous class is always an inner class; it is never
static
.
An instance of an inner class
I
whose declaration occurs in a static context has no lexically enclosing instances.
To help understand how this works, here is a formatted example:
class Example { public static void main(String... args) { new Object() { int i; void m() {} }; } }
Everything in italics
is the static context. The anonymous class derived from the expression in bold
is considered inner and non-static (but has no enclosing instance of Example
).
Since the anonymous class is non-static it cannot declare static non-constant members, despite that it is itself declared within a static context.
* Besides obscuring the matter a little, the fact that Operation
is an enum is completely irrelevant (8.9.1):
The optional class body of an enum constant implicitly defines an anonymous class declaration that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes [...].
I don't think I have the answer about the nature of the error, but perhaps I can contribute a bit to the discussion.
When the Java compiler compiles your enum code, it produces a synthetic class that is somewhat as follows:
class Operation { protected abstract void foo(); private void bar(){ } public static final Operation ONE; static { ONE = new Operation() { @Override protected void foo(){ bar(); } }; } }
You can verify the enum code looks somewhat like this by running javap in one of your enum classes.
This code above gives me the exact same error you're getting on your enum: "error: non-static method bar() cannot be referenced from a static context".
So here the compiler thinks you cannot invoke the bar()
method, which is an instance method, from the static context in which the anonymous class is being defined.
It makes no sense to me, it should either be accesible or be denied access, but the error does not seem accurate. I am still puzzled, but this seems to be what is actually happening.
It would make more sense if the compilers said that that the anonymous class did not have access to foo
since it is private on its parent class, but the compiler is firing this other error instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With