tags:

views:

482

answers:

6

The syntax sugar provided by Java's enum facility can sometimes be a little confusing. Consider this example, which does not compile:

public enum TestEnum {

    FOO("foo") {
        public void foo() {
            helper();  // <- compiler error
        }
    };

    String name;
    TestEnum(String name) {
        this.name = name;
    }

    public abstract void foo();

    private void helper(){
        // do stuff (using this.name, so must not be static)
    }
}

Can anyone explain why the compiler says

Non-static method 'helper()' cannot be referenced from a static context

How exactly is this context static?

You can make this compile by changing the call to this.helper() (here is one confusing point: if we really are in a "static context" like the compiler suggests, how can "this" work?) or by increasing the visibility of helper() to default level. Which would you prefer? Also, feel free to suggest a better question title :-)

Edit: I found some discussion about this - but no real answers. My colleague thinks the fact that that this.helper() works is actually a compiler bug. And indeed with newer Java versions it seems not to work (although super.helper() does): "cannot find symbol helper()". (Although there's something odd going on: after trying with different Java versions I can't get this.helper() to compile again with any of them...)

A: 

There is an article mentioning this problem, unfortunately it is in German. Maybe you can still extract some useful info.

EDIT: Seems to be a somewhat different problem from yours. I still don't understand the behaviour of your example, which I also see here.

starblue
+2  A: 

Something like this is covered in the Java Puzzlers book. IIRC, the outer class context is always looked at before the super class. In this case helper is found. But we are constructing the value in a static context (there's effectively a private static final before FOO). Hence the error.

Try super.helper();.

Tom Hawtin - tackline
I have the book; which puzzle do you mean? (I couldn't find it quickly.)
Jonik
Both my copies of the book are packed away in boxes somewhere, so I have no idea.
Tom Hawtin - tackline
+2  A: 

If i translate your enum into it's class structure it will look approximately like this:

public abstract class TestEnum {

  public static final TestEnum FOO = new FOO("foo") {
    public void foo() {
        helper();  // <- compiler error
    }
 };

  String name;
  TestEnum(String name) {
      this.name = name;
  }

  public abstract void foo();

  private void helper(){
    // do stuff (using this.name, so must not be static)
  }

}

The instance FOO is an anynomous class that extends TestEnum. That's why I believe you can't access helper(), because it is private. So this.helper() probably shouldn't work. i'm not sure why even super.helper() works, but maybe enum gives you private access to the parent.

As for the static context error, i agree the error message doesn't seem to make sense.

richs
Nitpick: with "new FOO" did you mean "new TestEnum"?
Jonik
yeah caught that also.. thanks
richs
+3  A: 

The error message is misleading, just make helper protected and it will work.

protected void helper(){
    // can be called from subclasses (such as FOO) since it is not private
}
Adrian
A: 

You can think of each enum constant as the only instance of a sub-class of the enum class. Just like with "regular" classes, the enum "sub-classes" cannot access private members of the enum "super-class." (I can't recreate the "this." work-around that you mention.)

A reasonable solution is to change the method access from private to protected to give access to the enum constant "sub-classes."

Better question title suggestion: "Java private enum method?" or just "Private enum method" (let the Java tag take care of the Java-ness)

Greg Mattes
A: 

I get the same error with a public helper(). Calling super.helper()... helped.