Why can't I make enum a public class?

Checking some things, I tried to make enum in which each element in the enumeration has a different class inside.

Take for example:

public enum MyEnum { first{ class First{} }, second { class Second{} }; } 

If I try to put a public modifier in front of any class, a modifier that is not allowed here appears. I do not quite understand why this would be. I cannot create instances of these classes outside of the enumeration and not see them. However, I can get the instance like this:

 public enum MyEnum { first{ class First{} public Object getObject(){ return new First(); } }, second { class Second{} public Object getObject(){ return new Second(); } }; public abstract Object getObject(); } public class Main { public static void main(String[] args) { System.out.println(MyEnum.first.getObject().getClass()); System.out.println(MyEnum.second.getObject().getClass()); } } 

With an exit:

class MyEnum $ 1 $ First

class MyEnum $ 2 $ Second

I can explicitly refer to this class, why can't I access it at compile time?

+5
source share
2 answers

This is a very interesting question. You will not be able to access these classes at compile time, even if the public modifier was enabled, because they are contained in implicitly anonymous classes, so in any case they can be accessed by name (in addition to the anonymous class). You cannot access the type through a variable, i.e. Access to MyEnum.first.First is not possible at all in Java.

However, it is not useful to not necessarily determine what can be declared, i.e. declare the inner class public inside the outer class private . Formal rules are relevant, and although this looks like expected behavior at first glance, it is unexpectedly not supported by the specification in this way.

JLS §8.9.1, Enum Constants states:

The optional body of the enum constant class implicitly defines an anonymous class declaration ( §15.9.5 ), which extends the immediately included enumeration type. The class body is defined by the usual rules of anonymous classes ...

which gives us an interesting hint, i.e.

 class Outer { static Object o = new Object() { public class Inner { } }; } 

also rejected by the compiler.

Given JLS, §8.1.1. Class Modifiers :

The public access public ( §6.6 ) applies only to top-level classes ( §7.6 ) and member classes ( §8.5 ), not local classes ( §14.3 ) or anonymous classes ( §15.9.5 ).

we must decide in which category Inner or your First class falls. It is not that their surrounding class is an anonymous class. Obviously, they are neither upper nor anonymous, since they are nested and have a name. Thus, they must be either a member class ( public allowed) or a local class ( public not allowed).

JLS, §8.5. Member Type Ads :

A member class is a class whose declaration is directly enclosed in the body of another class or interface declaration ( §8.1.6 , §9.1.4 ).

"The body of another class ... declaration" is defined by specifying §8.1.6 , which really defines the grammar of the ClassBody language, which is commonly used by named declarations , anonymous classes and enum constant bodies ; they all point to a “cool body” in §8.1.6. Given this, our classes are "member classes" because they are contained in the body of the class.

Now we could try to interpret this as an incorrect cross-reference, believing that the "body of another class ... declaration" meant a link to Class declarations , i.e. named class declarations using the class keyword, however, there is a definition of local classes that refutes this interpretation.

JLS §14.3, Local classes :

A local class is a nested class ( §8 (classes) ) that is not a member of any class and has a name ( §6.2 , §6.7 ).

...

Each local class declaration request is immediately contained in a block ( §14.2 ). Local class declaration statements can mix freely with other types of statements in a block.

“Block” actually means a block, as the definition of a non- abstract method, constructor or initializer ( §14.2 ). This does not apply to the Inner class above or to your First and Second classes. They do not fit into the block and cannot be mixed freely with operators in this context, because the arent statement is allowed at this point.

In other words, they are definitely not local classes and suggest that there is no other category of classes not described in the specification, we should consider their member classes, since the current letter and relationship of the definition of member classes will also be assumed, in other words, according to the indicated rules, the public modifier must be enabled in this place .

For completeness, here is the definition of anonymous classes, just to show that there is no exclusive rule saying that their members of the class arent allowed to be public :

15.9.5. Anonymous class declarations

An anonymous class declaration is automatically inferred from the Java class compiler instantiation expression.

An anonymous class is never abstract (§8.1.1.1).

An anonymous class is always implicitly final (§8.1.1.2).

An anonymous class is always an inner class (§8.1.3); it is never static (§8.1.1, §8.5.1).

It follows from the last point that, in turn, their member classes cannot be static , however, there is no rule prohibiting them from being public .

+4
source

You subclass MyEnum with your current approach (the {} syntax creates an anonymous subclass), which works, but seems too complicated. What you have is equivalent to something like

 public enum MyEnum { first, second; // <-- convention would be FIRST, SECOND public static class First { // <-- can be public. } public static class Second { } public Object getObject() { if (this == first) { return new First(); } return new Second(); } } 
+3
source

All Articles