11

So I have my enum

public enum Sample {
   ValueA{
      @Override
   public String getValue(){ return "A"; }   
 },
 ValueB{
    @Override
   public String getValue(){ return "B"; }

   public void doSomething(){ }
 };
abstract public String getValue();
};

and I have some other code trying to use the enum.

Sample.ValueB.doSomething();

Which seems like it should be valid, but produces the error "The method doSomething() is undefined for the type Sample". As opposed to

Sample value = Sample.ValueB;
value.doSomething();

which produces the same error and seems reasonable.

I assume there is a reasonable answer as to why the first one doesn't work and it relates to the two examples being equivalent under the hood. I was hoping someone could point me towards the documentation on why it is that way.

3
  • It would really help if you'd say what error you're getting... Commented Aug 30, 2011 at 12:52
  • Shouldn't you call Sample.doSomething()? Commented Aug 30, 2011 at 12:53
  • 2
    @nfechner..the doSomething() method is not static.. Commented Aug 30, 2011 at 13:03

4 Answers 4

15

The type of the "field" ValueA is Sample. That means that you can only invoke methods on ValueA that Sample provides. From JLS §8.9.1. Enum Constants:

Instance methods declared in these class bodies may be invoked outside the enclosing enum type only if they override accessible methods in the enclosing enum type.

More importantly: From a design perspective enum values should be uniform: if some operation is possible with one specific value, then it should be possible with all values (although it might result in different code being executed).

Sign up to request clarification or add additional context in comments.

Comments

10

Basically the compile-time type of Sample.ValueB is still Sample, even though the execution-time type of the value will be ValueB. So your two snippets of code are equivalent - clients don't get to see the "extra" methods which are only present in some of your enum values.

You can effectively think of the enum as declaring a field like this:

public static final Sample ValueB = new Sample() {
    @Override
    public String getValue(){ return "B"; }

    public void doSomething(){ }
};

Comments

4

When you write

enum Sample
{
     Value{
        public void doSomething()
        {
              //do something
        }
    };
}

you are not creating an instance of the Sample enum, rather an instance of an anonymous sub-class of the enum Sample. Thet's why the method doSomething() is undefined.

Update: this can be proved as follows:

Try this

System.out.println(Sample.ValueB.getClass().getName());

prints Sample$2

Which means that even though you have the method doSomething() in the instance of Sample$2 which you have named ValueB, you are referring it through the super-class reference of type Sample and hence only those methods defined in the class Sample will be visible at compile time.

You can call that doSomething() at runtime via reflection though.

1 Comment

More importantly: the type of the "field" Value will still be Sample and not Sample$1.
3

public void doSomething(){ } will have same effect as private void doSomething(){ }.

doSomething() is not visible outside ValueB unless you add doSomething() to the Sample.

Each Sample value has type Sample, so it cannot have different set of methods for different values (from outside perspective).

2 Comments

Warning: the Sample values do have more specific types if they have a class body. The Sample fields only ever have the type Sample.
@Joachim: sure, but those specific types are anonymous subclasses of Sample, so "outside" you can only use interface defined by Sample. I didn't make my self clear - sorry.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.