Java enum and additional class files
I was just bit by this behavior and this question showed up when Googling. I thought I'd share the little bit of extra information I found out.
javac 1.5 and 1.6 create an additional synthetic class each time you use a switch on an enum. The class contains a so-called "switch map" which maps enum indices to switch table jump numbers. Importantly, the synthetic class is created for the class in which the switch occurs, not the enum class.
Here's an example of what gets generated:
EnumClass.java
public enum EnumClass { VALUE1, VALUE2, VALUE3 }
EnumUser.java
public class EnumUser {
public String getName(EnumClass value) {
switch (value) {
case VALUE1: return "value 1";
// No VALUE2 case.
case VALUE3: return "value 3";
default: return "other";
}
}
}
Synthetic EnumUser$1.class
class EnumUser$1 {
static final int[] $SwitchMap$EnumClass = new int[EnumClass.values().length];
static {
$SwitchMap$EnumClass[EnumClass.VALUE1.ordinal()] = 1;
$SwitchMap$EnumClass[EnumClass.VALUE3.ordinal()] = 2;
};
}
This switch map is then used to generate an index for a lookupswitch
or tableswitch
JVM instruction. It converts each enum value into a corresponding index from 1 to [number of switch cases].
EnumUser.class
public java.lang.String getName(EnumClass);
Code:
0: getstatic #2; //Field EnumUser$1.$SwitchMap$EnumClass:[I
3: aload_1
4: invokevirtual #3; //Method EnumClass.ordinal:()I
7: iaload
8: lookupswitch{ //2
1: 36;
2: 39;
default: 42 }
36: ldc #4; //String value 1
38: areturn
39: ldc #5; //String value 3
41: areturn
42: ldc #6; //String other
44: areturn
tableswitch
is used if there are three or more switch cases as it performs a more efficient constant-time lookup vs. lookupswitch
's linear search. Technically speaking javac could omit this whole business with the synthetic switch map when it uses lookupswitch
.
Speculation: I don't have Eclipse's compiler on hand to test with but I imagine that it doesn't bother with a synthetic class and simply uses lookupswitch
. Or perhaps it requires more switch cases than the original asker tested with before it "ugprades" to tableswitch
.
Why different class files are created for each enum type if they have constant-specific method?
Enums with constant-specific methods are implemented using anonymous inner classes. As mentioned in The Java Language Specification:
The optional class body of an enum constant implicitly defines an
anonymous class declaration (§15.9.5) that extends the immediately
enclosing enum type. The class body is governed by the usual rules of
anonymous classes; in particular it cannot contain any constructors.
Anonymous inner classes are implemented by creating class files with names like OuterClass$1
, OuterClass$2
etc., and this is exactly what happens in the case of the enum.
Why is an enum declared in a separate file, in Java?
Why is an enum declared in a separate file, in Java?
You don't have to declare an enum
in a separate file. You could do this:
public class Temperature {
public enum ScaleName {celsius, fahrenheit, kelvin, rankine};
private double number;
private ScaleName scale;
public Temperature() {
number = 0.0;
scale = ScaleName.fahrenheit;
}
...
}
The only difference between this and making the enum a top level class is that you now need to qualify the name of the enum when you use it in a different class.
But what is going on in my example is no different to what happens if the enum was any other static nested class. (A nested enum is implicitly static, so we don't need a static
keyword. See JLS 8.9.)
Why is this enum declared in its own file.
Because the code author chose to do it this way1.
Is there an advantage to this?
Yes. It means that don't have to qualify the enum
to use it ... in some circumstances where you would have to if the enum
was nested as above.
Actually, Java does allow you to put multiple top-level classes into the same source file provided that all but one of the classes is "package private". However, doing that is generally thought to be bad style, and it can be problematic for some tool chains ... I have heard.
1 - If you want to know the real reason why the authors of the textbook chose to do it that way, you would need to ask them!
Java more than one public Enum in one file
Your example from the question is nothing special for enums. The following compiles nicely.
public class MultiplePublicClassesInOneFile {
public static class StaticClass1 {
}
public static class StaticClass2 {
}
public class Class1 {
}
public class Class2 {
}
}
You can have any number of public nested classes within a class. It makes no difference whether they are enums or not. The rule may often be put informally You can have only one public class in a file, but the rule is only for top-level classes. Public nested classes are not limited by the rule.
And since the above works for public nested classes and since an enum is just a class, it of course works for nested enums too.
Public enums inside classes are not uncommon when they are used only or primarily with that class. They are usually declared static. Examples from the standard library include Character.UnicodeScript
, Thread.State
and Locale.Category
.
Multiple Enum Classes in One Java File 2
You have incorrect syntax.
Try something like this:
public class DERstring{
public enum Fertigkeit
{
UEBER("Überreden"),
HEIML("Heimlichkeit"),
SUCHE("Suchen");
private String name;
private Fertigkeit(String name){
this.name=name;
}
public String getName() {
return name;
}
}
.....other enums classes...
}
Referencing One of Multiple Enums in a Class File
Your real problem is how your XML parser interprets the value in <type>. If it does not know how to get an enum from within a class, then there is nothing you can do. On the other hand, it may know how to get at the enum, but uses some arcane delimiter to separate the class name from the enum name. So
<type>MyEnumContainer#MyEnum1</type>
<type>MyEnumContainer*MyEnum1</type>
or
<type>MyEnumContainer(MyEnum1)</type>
<type>MyEnumContainer[MyEnum1]</type>
or
<type enum="MyEnum1">MyEnumContainer</type>
<type inner="MyEnum1">MyEnumContainer</type>
or maybe even
<type-enum>MyEnumContainer.MyEnum1</type-enum>
Of course it could also be
<type>com.company.project.tools.MyEnumContainer.MyEnum1</type>
<type package="com.company.project.tools">MyEnumContainer.MyEnum1</type>
let your imagination run wild...
Multiple Enum Classes in one Java File
They can be three inner classes like this:
public class Types {
public enum Digits {...}
public enum Teens {...}
....
}
Then refer them Types.Digits.ONE
, Types.Teen.TWENTY
etc.
You can also use static imports like this:
import Types.Digits;
import Types.Teen;
..
in order to have shorter references: Digits.ONE
, Teen.TWENTY
etc.
Should Java enums be defined in their own files?
You can make it public
in the same class, only public class
should be defined in a separate Java file.
public class Card {
// ...
public enum CARD_SUITE { HEARTS, DIAMONDS, CLUBS, SPADES; }
}
You can then access the enum
like Card.CARD_SUITE.HEARTS
, Card.CARD_SUITE.DIAMONDS
...
Using Java enums from different classes?
An enum switch case label must be the unqualified name of an enum constant:
switch (test.getStatus()) // returns the current status
{
case Opened:
// do something
// break and other cases
}
It doesn't matter that it's defined within another class. In any case, the compiler is able to infer the type of the enum based on your switch
statement, and doesn't need the constant names to be qualified. For whatever reason, using qualified names is invalid syntax.
This requirement is specified by JLS §14.11:
SwitchLabel:
case ConstantExpression :
case EnumConstantName :
default :
EnumConstantName:
Identifier
(Thanks to Mark Peters' related post for the reference.)
Related Topics
Java Division by Zero Doesnt Throw an Arithmeticexception - Why
Changing Swing Jtable Cell Colors
Get Maven Artifact Version at Runtime
How to Disable Jsessionid in Tomcat Servlet
Is There an Equivalent of Java.Util.Regex for "Glob" Type Patterns
Spark SQL How to Explode Without Losing Null Values
Declaring and Initializing Variables Within Java Switches
What Does an Exclamation Mark Mean in Java
Spring: Why Do We Autowire the Interface and Not the Implemented Class
Dbcp - Validationquery for Different Databases
Why Equal Operator Works for Integer Value Until 128 Number
Spring Boot How to Hide Passwords in Properties File
Should I Call Ugi.Checktgtandreloginfromkeytab() Before Every Action on Hadoop