Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can enum implementations not access private fields in the enum class

Tags:

java

enums

I just answered this question by saying how to solve the compilation problem:

How to use fields in java enum by overriding the method?

But what I don't understand is why the error is happening in the first place.

Here is the example written as an enum:

public enum MyEnum {       FIRST {         @Override         public String doIt() {             return "1: " + someField; //error         }     },     SECOND {         @Override         public String doIt() {             return "2: " + super.someField; //no error         }     };      private String someField;       public abstract String doIt();  }  

Here is the exact same thing as abstract classes

abstract class MyClass {     class FIRST extends MyClass {         @Override         public String doIt() {             return "1: " + someField; //no error         }     };     class SECOND extends MyClass {         @Override         public String doIt() {             return "2: " + super.someField; //no error         }     };      private String someField;      public abstract String doIt(); } 

In the case of FIRST within the enum implementation it cannot access someField. However in the abstract class case it can.

Additionally adding super fixes the problem, as does removing the private modifier on the field.

Does anyone know why this slight quirk in the behaviour is happening?

like image 222
Tim B Avatar asked Jul 29 '14 08:07

Tim B


People also ask

Should enum be private?

An enum is a type, not a data member. You should make it public if users of the class need to know about it; otherwise, make it private. A typical situation where users need to know about it is when it's used as the type of an argument to a public member function.

Does enum need to be public?

Yes, you do have to declare that enum public. You shouldn't have to have it in its own file. You would access just like your example Student.

Can we use private modifier in enum?

Now, you know that Enum can have a constructor in Java that can be used to pass data to Enum constants, just like we passed action here. Though Enum constructor cannot be protected or public, it can either have private or default modifier only.

Can enum have private variables?

Enum FieldsThe enum constructor must be private . You cannot use public or protected constructors for a Java enum . If you do not specify an access modifier the enum constructor it will be implicitly private .


2 Answers

Your abstract class is not equivalent to your enum, since enums are implicitly public static final. Thus, you'll observe the same behavior if you use:

abstract class MyClass {      static class FIRST extends MyClass {          @Override         public String doIt() {             return "1: " + someField; // error         }      };      static class SECOND extends MyClass {          @Override         public String doIt() {             return "2: " + super.someField; // no error         }      };      private String someField;      public abstract String doIt();  } 

As explained in http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html, chapter "Static Nested Classes":

A static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference.

Thus the need of super. You could also use this if the field were protected rather than private.

like image 129
sp00m Avatar answered Oct 14 '22 01:10

sp00m


When an identifier is resolved, Java prefers the lexical scope over inherited members. So when you have an inner class that extends the outer class and use a field of the outer class without using this or super, the field of the outer instance is accessed which fails if the inner class is static as there is no outer instance then. In contrast, when using super you are explicitly accessing the inherited member. Note that enum classes are implicitly static. You can even use this to access the inherited member but you have to use ((MyClass)this).someField to access it if it’s declared private.

like image 37
Holger Avatar answered Oct 14 '22 01:10

Holger