switch之enum

Posted on

switch之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

  1. //////////////////////////////////////*
  2. /////////////////////////////////////*
  3. 源代码
  4. /////////////////////////////////////*
  5. /////////////////////////////////////*/
  6. public static void testSwitchInt() {
  7. int intElement = 3;
  8. switch (intElement) {
  9. case 3:
  10. System.out.println("3");
  11. break;
  12. default:
  13. System.out.println("int DEFAULT");
  14. break;
  15. }
  16. }
  17. //int 类型反编译跟源代码是一样的
  18. //////////////////////////////////////*
  19. /////////////////////////////////////*
  20. 用javap工具看class指令
  21. /////////////////////////////////////*
  22. /////////////////////////////////////*/
  23. //case 的值本来就是int,这没什么好说的
  24. public static void testSwitchInt();
  25. Code:
  26. Stack=2, Locals=1, Args_size=0
  27. 0: iconst_3 //解释:加载int常量3
  28. 1: istore_0 //解释:保存int类型到局部变量表index为0的位置(其实保存的就是3)
  29. 2: iload_0 //加载局部变量表index为0的位置的int变量,用于switch里面
  30. 3: lookupswitch{ //1
  31. 3: 20;
  32. default: 31 }
  33. 20: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
  34. 23: ldc /#13; //String 3
  35. 25: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
  36. ring;)V
  37. 28: goto 39
  38. 31: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
  39. 34: ldc /#14; //String int DEFAULT
  40. 36: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
  41. ring;)V
  42. 39: return


  43. //////////////////////////////////////*
  44. /////////////////////////////////////*
  45. 源代码
  46. /////////////////////////////////////*
  47. /////////////////////////////////////*/
  48. public static void testSwitchChar() {
  49. int charElement = 'a'; //ascii对应的是97,编译器直接把这个值编译成97,case里面也是这样的
  50. switch (charElement) {
  51. case 'a':
  52. System.out.println("a");
  53. break;
  54. default:
  55. System.out.println("char DEFAULT");
  56. break;
  57. }
  58. }
  59. //////////////////////////////////////*
  60. /////////////////////////////////////*
  61. 编译后的代码
  62. /////////////////////////////////////*
  63. /////////////////////////////////////*/
  64. public static void testSwitchChar()
  65. {
  66. int charElement = 97;
  67. switch(charElement)
  68. {
  69. case 97: // 'a'
  70. System.out.println("a");
  71. break;
  72. default:
  73. System.out.println("char DEFAULT");
  74. break;
  75. }
  76. }
  77. //////////////////////////////////////*
  78. /////////////////////////////////////*
  79. 用javap工具看class指令
  80. /////////////////////////////////////*
  81. /////////////////////////////////////*/
  82. //case 的值本来就是char类型,但被编译器处理成int
  83. public static void testSwitchChar();
  84. Code:
  85. Stack=2, Locals=1, Args_size=0
  86. 0: bipush 97 //解释:加载int常量97,a的ascii码
  87. 2: istore_0 //接下来和上面都一样的
  88. 3: iload_0
  89. 4: tableswitch{ //97 to 97
  90. 97: 24;
  91. default: 35 }
  92. 24: getstatic /#46; //Field java/lang/System.out:Ljava/io/PrintStream;
  93. 27: ldc /#68; //String a
  94. 29: invokevirtual /#53; //Method java/io/PrintStream.println:(Ljava/lang/St
  95. ring;)V
  96. 32: goto 43
  97. 35: getstatic /#46; //Field java/lang/System.out:Ljava/io/PrintStream;
  98. 38: ldc /#70; //String char DEFAULT
  99. 40: invokevirtual /#53; //Method java/io/PrintStream.println:(Ljava/lang/St
  100. ring;)V
  101. 43: return
  102. byte short 也是同理,都会编译成int


  103. /////////////////////////上面的例子都比较好理解,enum大家可能也会有点疑惑/////////////////////////////////
  104. //////////////////////////////////////*
  105. /////////////////////////////////////*
  106. 源代码
  107. /////////////////////////////////////*
  108. /////////////////////////////////////*/
  109. enum EnumTest {
  110. WINTER, SUMMER, SPRING, AUTUMN;
  111. }
  112. public static void testSwitchEnum() {
  113. EnumTest enumElement = EnumTest.AUTUMN;
  114. switch (enumElement) {
  115. case AUTUMN:
  116. System.out.println("AUTUMN");
  117. break;
  118. default:
  119. System.out.println("enum DEFAULT");
  120. break;
  121. }
  122. }
  123. //////////////////////////////////////*
  124. /////////////////////////////////////*
  125. enum类编译后的代码
  126. /////////////////////////////////////*
  127. /////////////////////////////////////*/
  128. //enum其实也就是个普通的类,继承Enum
  129. public final class EnumTest extends Enum
  130. {
  131. private EnumTest(String s, int i)
  132. {
  133. super(s, i);
  134. //*调用父类的构造函数
  135. protected Enum(String name, int ordinal) {
  136. this.name = name; //名称
  137. this.ordinal = ordinal; 元素位置
  138. }
  139. /*/
  140. }
  141. public static EnumTest[] values()
  142. {
  143. EnumTest aenumtest[];
  144. int i;
  145. EnumTest aenumtest1[];
  146. System.arraycopy(aenumtest = ENUM$VALUES, 0, aenumtest1 = new EnumTest[i = aenumtest.length], 0, i);
  147. return aenumtest1;
  148. }
  149. public static EnumTest valueOf(String s)
  150. {
  151. return (EnumTest)Enum.valueOf(meiju/EnumTest, s);
  152. }
  153. public static final EnumTest WINTER;
  154. public static final EnumTest SUMMER;
  155. public static final EnumTest SPRING;
  156. public static final EnumTest AUTUMN;
  157. private static final EnumTest ENUM$VALUES[];
  158. static
  159. {
  160. //enum的位置的排好的,想数组一样,enum元素最终都保存在ENUM$VALUES数组
  161. WINTER = new EnumTest("WINTER", 0);
  162. SUMMER = new EnumTest("SUMMER", 1);
  163. SPRING = new EnumTest("SPRING", 2);
  164. AUTUMN = new EnumTest("AUTUMN", 3);
  165. ENUM$VALUES = (new EnumTest[] {
  166. WINTER, SUMMER, SPRING, AUTUMN
  167. });
  168. }
  169. }
  170. //////////////////////////////////////*
  171. /////////////////////////////////////*
  172. testSwitchEnum方法编译后的代码
  173. /////////////////////////////////////*
  174. /////////////////////////////////////*/
  175. 用到enum元素,所以会在当前类中多生成一个$SWITCH_TABLE$meiju$EnumTest()方法和$SWITCH_TABLE$meiju$EnumTest[]变量,用于switch
  176. static int[] $SWITCH_TABLE$meiju$EnumTest()
  177. {
  178. $SWITCH_TABLE$meiju$EnumTest;
  179. if($SWITCH_TABLE$meiju$EnumTest == null) goto _L2; else goto _L1
  180. _L1:
  181. return;
  182. _L2:
  183. JVM INSTR pop ;
  184. int ai[] = new int[EnumTest.values().length];
  185. try
  186. {
  187. ai[EnumTest.AUTUMN.ordinal()] = 4;
  188. }
  189. catch(NoSuchFieldError _ex) { }
  190. try
  191. {
  192. ai[EnumTest.SPRING.ordinal()] = 3;
  193. }
  194. catch(NoSuchFieldError _ex) { }
  195. try
  196. {
  197. ai[EnumTest.SUMMER.ordinal()] = 2;
  198. }
  199. catch(NoSuchFieldError _ex) { }
  200. try
  201. {
  202. ai[EnumTest.WINTER.ordinal()] = 1;
  203. }
  204. catch(NoSuchFieldError _ex) { }
  205. return $SWITCH_TABLE$meiju$EnumTest = ai;
  206. }
  207. private static int $SWITCH_TABLE$meiju$EnumTest[];//保存的是enum的index
  208. public static void testSwitchEnum()
  209. {
  210. EnumTest enumElement = EnumTest.AUTUMN;
  211. //这个就是上面所用到的变量
  212. switch($SWITCH_TABLE$meiju$EnumTest()[enumElement.ordinal()])
  213. {
  214. case 4: // '/004' 因为enum类的元素其实就是个常量,在编译阶段就能确定值,在源代码的case AUTUMN: 其实也就被他所在的ordinal()给替换掉了,其实就是索引
  215. System.out.println("AUTUMN");
  216. break;
  217. default:
  218. System.out.println("enum DEFAULT");
  219. break;
  220. }
  221. }
  222. //////////////////////////////////////*
  223. /////////////////////////////////////*
  224. 用javap工具看class指令
  225. /////////////////////////////////////*
  226. /////////////////////////////////////*/
  227. public static void testSwitchEnum();
  228. Code:
  229. Stack=2, Locals=1, Args_size=0
  230. 0: getstatic /#6; //Field meiju/EnumTest.AUTUMN:Lmeiju/EnumTest;
  231. 3: astore_0
  232. 4: getstatic /#7; //Field meiju/SwitchEnum$1.$SwitchMap$meiju$EnumTest
  233. :[I
  234. 7: aload_0
  235. 8: invokevirtual /#8; //Method meiju/EnumTest.ordinal:()I
  236. 11: iaload
  237. 12: lookupswitch{ //1
  238. 1: 32;
  239. default: 43 }
  240. 32: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
  241. 35: ldc /#10; //String AUTUMN
  242. 37: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
  243. ring;)V
  244. 40: goto 51
  245. 43: getstatic /#9; //Field java/lang/System.out:Ljava/io/PrintStream;
  246. 46: ldc /#12; //String enum DEFAULT
  247. 48: invokevirtual /#11; //Method java/io/PrintStream.println:(Ljava/lang/St
  248. ring;)V
  249. 51: return

事实证明当时他不是忽悠我,确实是这样的:)

来源: [http://blog.csdn.net/wzju64676266/article/details/6140871](http://blog.csdn.net/wzju64676266/article/details/6140871)

希望本站内容对您有点用处,有什么疑问或建议请在后面留言评论
转载请注明作者(RobinChia)和出处 It so life ,请勿用于任何商业用途
本文链接: switch之enum