switch之enum
Posted onswitch之enum
switch之enum
2011-01-14 23:46 springtableclassstring编译器byte
记得曾经去一家公司面试,那时啥也不懂,面试我的那个人好像呆过IBM,数据结构、编译原理这些都很NB。
问答环节
他:java switch中能支持什么类型?
我:byte short char int ,jdk1.5出来了enum,同样也支持enum
他:为什么能支持byte short char int 而long不行?
我:这个可能是设计问题
他:其实jvm执行class文件的时候,byte short char int这些都是当int类型来执行的,long不能直接转换成int,编译阶段就通不过了。
我:我那个时候不太理解他说的那个意思,只能点点头
他:好,那接着讨论switch为什么支持enum,刚才也讨论过switch其实都是int类型,也只支持int,那enum不是int类型,是个对象,那为什么支持呢!
我:那个时候我就蒙了(心里想着,你这家伙,就胡扯),但我讲不出理由,就直接说不知道
他:其实在switch中enum也是int类型
我:心想----我不知道你说的是对还是错,你怎么说都行
自从那以后,哥去研究虚拟机,java指令
好,废话不多说了,现在来看一下代码,代码比较简单!
[java] view plaincopy
- //////////////////////////////////////*
- /////////////////////////////////////*
- 源代码
- /////////////////////////////////////*
- /////////////////////////////////////*/
- public static void testSwitchInt() {
- int intElement = 3;
- switch (intElement) {
- case 3:
- System.out.println("3");
- break;
- default:
- System.out.println("int DEFAULT");
- break;
- }
- }
- //int 类型反编译跟源代码是一样的
- //////////////////////////////////////*
- /////////////////////////////////////*
- 用javap工具看class指令
- /////////////////////////////////////*
- /////////////////////////////////////*/
- //case 的值本来就是int,这没什么好说的
- public static void testSwitchInt();
- Code:
- Stack=2, Locals=1, Args_size=0
- 0: iconst_3 //解释:加载int常量3
- 1: istore_0 //解释:保存int类型到局部变量表index为0的位置(其实保存的就是3)
- 2: iload_0 //加载局部变量表index为0的位置的int变量,用于switch里面
- 3: lookupswitch{ //1
- 3: 20;
- default: 31 }
- 20: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
- 23: ldc /#13; //String 3
- 25: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
- ring;)V
- 28: goto 39
- 31: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
- 34: ldc /#14; //String int DEFAULT
- 36: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
- ring;)V
- 39: return
- //////////////////////////////////////*
- /////////////////////////////////////*
- 源代码
- /////////////////////////////////////*
- /////////////////////////////////////*/
- public static void testSwitchChar() {
- int charElement = 'a'; //ascii对应的是97,编译器直接把这个值编译成97,case里面也是这样的
- switch (charElement) {
- case 'a':
- System.out.println("a");
- break;
- default:
- System.out.println("char DEFAULT");
- break;
- }
- }
- //////////////////////////////////////*
- /////////////////////////////////////*
- 编译后的代码
- /////////////////////////////////////*
- /////////////////////////////////////*/
- public static void testSwitchChar()
- {
- int charElement = 97;
- switch(charElement)
- {
- case 97: // 'a'
- System.out.println("a");
- break;
- default:
- System.out.println("char DEFAULT");
- break;
- }
- }
- //////////////////////////////////////*
- /////////////////////////////////////*
- 用javap工具看class指令
- /////////////////////////////////////*
- /////////////////////////////////////*/
- //case 的值本来就是char类型,但被编译器处理成int
- public static void testSwitchChar();
- Code:
- Stack=2, Locals=1, Args_size=0
- 0: bipush 97 //解释:加载int常量97,a的ascii码
- 2: istore_0 //接下来和上面都一样的
- 3: iload_0
- 4: tableswitch{ //97 to 97
- 97: 24;
- default: 35 }
- 24: getstatic /#46; //Field java/lang/System.out:Ljava/io/PrintStream;
- 27: ldc /#68; //String a
- 29: invokevirtual /#53; //Method java/io/PrintStream.println:(Ljava/lang/St
- ring;)V
- 32: goto 43
- 35: getstatic /#46; //Field java/lang/System.out:Ljava/io/PrintStream;
- 38: ldc /#70; //String char DEFAULT
- 40: invokevirtual /#53; //Method java/io/PrintStream.println:(Ljava/lang/St
- ring;)V
- 43: return
- byte short 也是同理,都会编译成int
- /////////////////////////上面的例子都比较好理解,enum大家可能也会有点疑惑/////////////////////////////////
- //////////////////////////////////////*
- /////////////////////////////////////*
- 源代码
- /////////////////////////////////////*
- /////////////////////////////////////*/
- enum EnumTest {
- WINTER, SUMMER, SPRING, AUTUMN;
- }
- public static void testSwitchEnum() {
- EnumTest enumElement = EnumTest.AUTUMN;
- switch (enumElement) {
- case AUTUMN:
- System.out.println("AUTUMN");
- break;
- default:
- System.out.println("enum DEFAULT");
- break;
- }
- }
- //////////////////////////////////////*
- /////////////////////////////////////*
- enum类编译后的代码
- /////////////////////////////////////*
- /////////////////////////////////////*/
- //enum其实也就是个普通的类,继承Enum
- public final class EnumTest extends Enum
- {
- private EnumTest(String s, int i)
- {
- super(s, i);
- //*调用父类的构造函数
- protected Enum(String name, int ordinal) {
- this.name = name; //名称
- this.ordinal = ordinal; 元素位置
- }
- /*/
- }
- public static EnumTest[] values()
- {
- EnumTest aenumtest[];
- int i;
- EnumTest aenumtest1[];
- System.arraycopy(aenumtest = ENUM$VALUES, 0, aenumtest1 = new EnumTest[i = aenumtest.length], 0, i);
- return aenumtest1;
- }
- public static EnumTest valueOf(String s)
- {
- return (EnumTest)Enum.valueOf(meiju/EnumTest, s);
- }
- public static final EnumTest WINTER;
- public static final EnumTest SUMMER;
- public static final EnumTest SPRING;
- public static final EnumTest AUTUMN;
- private static final EnumTest ENUM$VALUES[];
- static
- {
- //enum的位置的排好的,想数组一样,enum元素最终都保存在ENUM$VALUES数组
- WINTER = new EnumTest("WINTER", 0);
- SUMMER = new EnumTest("SUMMER", 1);
- SPRING = new EnumTest("SPRING", 2);
- AUTUMN = new EnumTest("AUTUMN", 3);
- ENUM$VALUES = (new EnumTest[] {
- WINTER, SUMMER, SPRING, AUTUMN
- });
- }
- }
- //////////////////////////////////////*
- /////////////////////////////////////*
- testSwitchEnum方法编译后的代码
- /////////////////////////////////////*
- /////////////////////////////////////*/
- 用到enum元素,所以会在当前类中多生成一个$SWITCH_TABLE$meiju$EnumTest()方法和$SWITCH_TABLE$meiju$EnumTest[]变量,用于switch
- static int[] $SWITCH_TABLE$meiju$EnumTest()
- {
- $SWITCH_TABLE$meiju$EnumTest;
- if($SWITCH_TABLE$meiju$EnumTest == null) goto _L2; else goto _L1
- _L1:
- return;
- _L2:
- JVM INSTR pop ;
- int ai[] = new int[EnumTest.values().length];
- try
- {
- ai[EnumTest.AUTUMN.ordinal()] = 4;
- }
- catch(NoSuchFieldError _ex) { }
- try
- {
- ai[EnumTest.SPRING.ordinal()] = 3;
- }
- catch(NoSuchFieldError _ex) { }
- try
- {
- ai[EnumTest.SUMMER.ordinal()] = 2;
- }
- catch(NoSuchFieldError _ex) { }
- try
- {
- ai[EnumTest.WINTER.ordinal()] = 1;
- }
- catch(NoSuchFieldError _ex) { }
- return $SWITCH_TABLE$meiju$EnumTest = ai;
- }
- private static int $SWITCH_TABLE$meiju$EnumTest[];//保存的是enum的index
- public static void testSwitchEnum()
- {
- EnumTest enumElement = EnumTest.AUTUMN;
- //这个就是上面所用到的变量
- switch($SWITCH_TABLE$meiju$EnumTest()[enumElement.ordinal()])
- {
- case 4: // '/004' 因为enum类的元素其实就是个常量,在编译阶段就能确定值,在源代码的case AUTUMN: 其实也就被他所在的ordinal()给替换掉了,其实就是索引
- System.out.println("AUTUMN");
- break;
- default:
- System.out.println("enum DEFAULT");
- break;
- }
- }
- //////////////////////////////////////*
- /////////////////////////////////////*
- 用javap工具看class指令
- /////////////////////////////////////*
- /////////////////////////////////////*/
- public static void testSwitchEnum();
- Code:
- Stack=2, Locals=1, Args_size=0
- 0: getstatic /#6; //Field meiju/EnumTest.AUTUMN:Lmeiju/EnumTest;
- 3: astore_0
- 4: getstatic /#7; //Field meiju/SwitchEnum$1.$SwitchMap$meiju$EnumTest
- :[I
- 7: aload_0
- 8: invokevirtual /#8; //Method meiju/EnumTest.ordinal:()I
- 11: iaload
- 12: lookupswitch{ //1
- 1: 32;
- default: 43 }
- 32: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
- 35: ldc /#10; //String AUTUMN
- 37: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
- ring;)V
- 40: goto 51
- 43: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
- 46: ldc /#12; //String enum DEFAULT
- 48: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
- ring;)V
- 51: return
事实证明当时他不是忽悠我,确实是这样的:)