Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java public enum method purpose

Tags:

java

enums

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.

like image 445
Sign Avatar asked Aug 30 '11 12:08

Sign


3 Answers

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).

like image 99
Joachim Sauer Avatar answered Sep 27 '22 16:09

Joachim Sauer


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(){ }
};
like image 21
Jon Skeet Avatar answered Sep 27 '22 16:09

Jon Skeet


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.

like image 33
Swaranga Sarma Avatar answered Sep 27 '22 16:09

Swaranga Sarma