Which you and I would both expect, since we know that
Integer x;
switch(x) ...
is short for
Integer x;
switch (x.intValue()) ...
I wonder, then, is
Enum e;
switch(e)...
short for
Enum e;
switch (e.ordinal())...
(Checks...) Yes it is, which explains the NPE, but geez, that's fragile.
Change the order of the enum constants, forget to recompile the world,
and
your switches do entirely the wrong thimg.
You've under-estimated just how much time Sun spends on ensuring Binary
compatability.
Given:
<sscce>
package pkg1;
public class EnumDisassembly {
public static Letter getLetter() {
return Letter.A;}
public static void main(String[] args) {
switch (getLetter()) {
case A: System.out.println("ABC"); break;
case B: System.out.println("BCD"); break;
case C: System.out.println("CDE");
}
}
enum Letter {A, B, C}
}
<sscce>
You will notice not 2, but 3 classes (I'm using jdk1.6.0_02 for reference)
EnumDisassembly.class, EnumDisassembly$Letter.class, and
EnumDisassembly$1.class
Take a peek at our EnumDisassembly.main(), and look at the first line!
public static void main(java.lang.String[]);
Code:
0: getstatic #3; //Field
pkg1/EnumDisassembly$1.$SwitchMap$pkg1$EnumDisassembly$Letter:[I
3: invokestatic #4; //Method getLetter
)Lpkg1/EnumDisassembly$Letter;
6: invokevirtual #5; //Method pkg1/EnumDisassembly$Letter.ordinal
)I
9: iaload
10: tableswitch{ //1 to 3
1: 36;
2: 47;
3: 58;
default: 66 }
36: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
39: ldc #7; //String ABC
41: invokevirtual #8; //Method
java/io/PrintStream.println
Ljava/lang/String
V
44: goto 66
47: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #9; //String BCD
52: invokevirtual #8; //Method
java/io/PrintStream.println
Ljava/lang/String
V
55: goto 66
58: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
61: ldc #10; //String CDE
63: invokevirtual #8; //Method
java/io/PrintStream.println
Ljava/lang/String
V
66: return
LineNumberTable:
line 8: 0
line 9: 36
line 10: 47
line 11: 58
line 12: 66
}
And, looking at our synthetic $1 we see:
Compiled from "EnumDisassembly.java"
class pkg1.EnumDisassembly$1 extends java.lang.Object{
static final int[] $SwitchMap$pkg1$EnumDisassembly$Letter;
static {};
Code:
0: invokestatic #1; //Method
pkg1/EnumDisassembly$Letter.values
)[Lpkg1/EnumDisassembly$Letter;
3: arraylength
4: newarray int
6: putstatic #2; //Field $SwitchMap$pkg1$EnumDisassembly$Letter:[I
9: getstatic #2; //Field $SwitchMap$pkg1$EnumDisassembly$Letter:[I
12: getstatic #3; //Field
pkg1/EnumDisassembly$Letter.A:Lpkg1/EnumDisassembly$Letter;
15: invokevirtual #4; //Method pkg1/EnumDisassembly$Letter.ordinal
)I
18: iconst_1
19: iastore
20: goto 24
23: astore_0
24: getstatic #2; //Field $SwitchMap$pkg1$EnumDisassembly$Letter:[I
27: getstatic #6; //Field
pkg1/EnumDisassembly$Letter.B:Lpkg1/EnumDisassembly$Letter;
30: invokevirtual #4; //Method pkg1/EnumDisassembly$Letter.ordinal
)I
33: iconst_2
34: iastore
35: goto 39
38: astore_0
39: getstatic #2; //Field $SwitchMap$pkg1$EnumDisassembly$Letter:[I
42: getstatic #7; //Field
pkg1/EnumDisassembly$Letter.C:Lpkg1/EnumDisassembly$Letter;
45: invokevirtual #4; //Method pkg1/EnumDisassembly$Letter.ordinal
)I
48: iconst_3
49: iastore
50: goto 54
53: astore_0
54: return
Exception table:
from to target type
9 20 23 Class java/lang/NoSuchFieldError
24 35 38 Class java/lang/NoSuchFieldError
39 50 53 Class java/lang/NoSuchFieldError
LineNumberTable:
line 8: 0
}
So, it appears that everytime you use a switch on an Enum, a new synthetic
class is created for you to load a $SwitchMap$ field, and thus populate
the correct ordinals. Thus, changing an Enum should be safe between full
compilations, so long as you don't delete a constant in someone else's
switchmap. Though, each class that uses a switch on an Enum create a new
synthetic class is a glaring downside to using the enhanced switch :/
HTH,
-Zig