| benf.org : other : cfr : How is switch-on-enum implemented? |
I looked at how Enums are implemented in java here.
Java has two bytecode switch instructions - TABLESWITCH and LOOKUPSWITCH. They both map from an integer (the value you're switching on) to a target bytecode address.
Given that Java's enums are objects, and not integers, how does the following get compiled?
public int test0(EnumTest1 e) {
switch (e) {
case FOO:
return 1;
case BAP:
return 2;
}
return 0;
}
It's a little more complicated than you might expect! (and involves an extra level of indirection)
The first enum -> integer function that springs to mind for an integer is .ordinal(). However - there are a couple of problems with this:
So we need a lookup function which isn't dependant on the ordinal of the enum value being fixed (i.e. resolves it at run time), and can cope with a field of the enum being removed.
(As of 0_7 cfr will correctly re-sugar switch on enum to the original code, unless you specify not to on the command line - here we specify not to...)
The switch statement above is changed to switch on an array lookup using the run time ordinal of the enum
public int test0(EnumTest1 e)
{
switch (SwitchTest2$1.$SwitchMap$org$benf$cfr$tests$EnumTest1[e.ordinal()]) {
case 1: {
return 1;
}
case 2: {
return 2;
}
default:
}
return 0;
}
This array is a static final member of an inner class, and is populated at run time to avoid the issues above... (Yes, there's a new inner class per switch-on-enum!)
class SwitchTest2$1
extends Object
{
// Fields
static final /* synthetic */ int[] $SwitchMap$org$benf$cfr$tests$EnumTest1;
// Methods
static void <clinit>()
{
SwitchTest2$1.$SwitchMap$org$benf$cfr$tests$EnumTest1 = new int[EnumTest1.values().length];
try {
SwitchTest2$1.$SwitchMap$org$benf$cfr$tests$EnumTest1[EnumTest1.FOO.ordinal()] = 1;
}
catch (NoSuchFieldError unnamed_local_ex_0) {
// empty catch block
}
try {
SwitchTest2$1.$SwitchMap$org$benf$cfr$tests$EnumTest1[EnumTest1.BAP.ordinal()] = 2;
}
catch (NoSuchFieldError unnamed_local_ex_0) {
// empty catch block
}
}
}
Note that NoSuchFieldErrors are ignored.
So the actual switch is done on an integer which is just the location of the target case in the original switch statement.....
| Last updated 08/2012 |