Java Enum and Additional Class Files

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



Leave a reply



Submit