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.
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).
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(){ }
};
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.
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