对于int的switch,jvm是用tableswitch和lookupswitch来实现的,jdk1.7 switch增加了对string的支持,那么底层是如何实现的呢?是否增加了新的指令或是否给某些指令增加了新的含义?

看这样一个程序:

Java代码  
  1. public class Test {
  2. public static void main(String[] args) {
  3. String name = "b";
  4. int value = 0;
  5. switch(name) {
  6. case "a":
  7. value = 1;
  8. break;
  9. case "b":
  10. value = 2;
  11. break;
  12. case "c":
  13. value = 3;
  14. break;
  15. case "d":
  16. value = 4;
  17. break;
  18. case "e":
  19. value = 5;
  20. break;
  21. default:
  22. value = 6;
  23. }
  24. System.out.println(value);
  25. }
  26. }

javap -c Test得出的结果为:

Java代码  
  1. public static void main(java.lang.String[]);
  2. Code:
  3. 0: ldc           #2                  // String b
  4. 2: astore_1                    //将"b"赋值给name
  5. 3: iconst_0                    //将0入栈
  6. 4: istore_2                    //将0赋值给value
  7. 5: aload_1                 //将name(即"b")入栈
  8. 6: astore_3                    //将name(即"b")赋值给一个编译器生成的变量,记为tmpName(tmpName此时也是"b")
  9. 7: iconst_m1                   //将-1入栈
  10. 8: istore        4         //将-1赋值给一个编译器生成的变量,记为m1
  11. 10: aload_3                 //将tmpName(即"b")入栈
  12. 11: invokevirtual #3                  // Method java/lang/String.hashCode:()I       调用tmpName的hashCode方法("b".hashCode(),得结果98)
  13. 14: tableswitch   { // 97 to 101        //根据hashCode的值到不同的分支
  14. 97: 48
  15. 98: 63                    //这里走到这个分支,跳转到63
  16. 99: 78
  17. 100: 93
  18. 101: 108
  19. default: 120
  20. }
  21. 48: aload_3
  22. 49: ldc           #4                  // String a
  23. 51: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  24. 54: ifeq          120
  25. 57: iconst_0
  26. 58: istore        4
  27. 60: goto          120
  28. 63: aload_3                         //从14跳转到了这里,将tmpName(即"b")入栈
  29. 64: ldc           #2                  // String b       将"b"入栈
  30. 66: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  31. //比较tmpName和"b",如果相等,将1入栈,不等将0入栈.这里是相等的,入栈的为1
  32. 69: ifeq          120                   //从栈顶取出比较结果,如果等于0,就跳到120,如果不等于0就继续下面的指令,这里显然不等于0
  33. 72: iconst_1                            //将1入栈
  34. 73: istore        4                 //将1存储到m1中
  35. 75: goto          120                   //跳到120
  36. 78: aload_3
  37. 79: ldc           #6                  // String c
  38. 81: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  39. 84: ifeq          120
  40. 87: iconst_2
  41. 88: istore        4
  42. 90: goto          120
  43. 93: aload_3
  44. 94: ldc           #7                  // String d
  45. 96: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  46. 99: ifeq          120
  47. 102: iconst_3
  48. 103: istore        4
  49. 105: goto          120
  50. 108: aload_3
  51. 109: ldc           #8                  // String e
  52. 111: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  53. 114: ifeq          120
  54. 117: iconst_4
  55. 118: istore        4
  56. 120: iload         4                 //将m1(即73行存进去的1)的值入栈
  57. 122: tableswitch   { // 0 to 4
  58. 0: 156
  59. 1: 161                   //这里走1这个分支,跳到161
  60. 2: 166
  61. 3: 171
  62. 4: 176
  63. default: 181
  64. }
  65. 156: iconst_1
  66. 157: istore_2
  67. 158: goto          184
  68. 161: iconst_2                    //将2入栈
  69. 162: istore_2                    //将2存储到value
  70. 163: goto          184           //跳转到184进行打印输出
  71. 166: iconst_3
  72. 167: istore_2
  73. 168: goto          184
  74. 171: iconst_4
  75. 172: istore_2
  76. 173: goto          184
  77. 176: iconst_5
  78. 177: istore_2
  79. 178: goto          184
  80. 181: bipush        6
  81. 183: istore_2
  82. 184: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
  83. 187: iload_2
  84. 188: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V
  85. 191: return

在这一堆指令中我们发现,jdk1.7并没有新指令来处理string switch,还是继续用lookupswitch和tableswitch两个指令来处理的,也没有扩展这两个指令,它们还是只能处理int。

在11行,我们看到调用了需要switch的string的hashCode方法,并对该hashCode进行switch,并跳转到相应的处理指令。跳到新的指令处我们发现这里(63行)将待switch的变量(name)与case中的值("b")equals了一下。这样做是为了避免不同的string有相同的hashCode,确定equals返回true后,编译器生成了一个处理value的switch,源码里有多少个case编译器生成的tableswitch就有多少个分支,最终会找到相应的处理分支完成string switch的处理。

接下来,看一个不同string hashCode相等的版本:

buzzards与righto的hashCode相等

hierarch与crinolines的hashCode相等

这里选择buzzards和righto

Java代码  
  1. public class Test {
  2. public static void main(String[] args) {
  3. String name = "buzzards";
  4. int value = 0;
  5. switch(name) {
  6. case "buzzards":
  7. value = 1;
  8. break;
  9. case "righto":
  10. value = 2;
  11. break;
  12. default:
  13. value = 6;
  14. }
  15. System.out.println(value);
  16. }
  17. }

字节码:

Java代码  
  1. public static void main(java.lang.String[]);
  2. Code:
  3. 0: ldc           #2                  // String buzzards
  4. 2: astore_1
  5. 3: iconst_0
  6. 4: istore_2
  7. 5: aload_1
  8. 6: astore_3
  9. 7: iconst_m1
  10. 8: istore        4
  11. 10: aload_3
  12. 11: invokevirtual #3                  // Method java/lang/String.hashCode:()I
  13. 14: lookupswitch  { // 1
  14. -931102253: 32
  15. default: 59
  16. }
  17. 32: aload_3
  18. 33: ldc           #4                  // String righto
  19. 35: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)
  20. 38: ifeq          47
  21. 41: iconst_1
  22. 42: istore        4
  23. 44: goto          59
  24. 47: aload_3
  25. 48: ldc           #2                  // String buzzards
  26. 50: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)
  27. 53: ifeq          59
  28. 56: iconst_0
  29. 57: istore        4
  30. 59: iload         4
  31. 61: lookupswitch  { // 2
  32. 0: 88
  33. 1: 93
  34. default: 98
  35. }
  36. 88: iconst_1
  37. 89: istore_2
  38. 90: goto          101
  39. 93: iconst_2
  40. 94: istore_2
  41. 95: goto          101
  42. 98: bipush        6
  43. 100: istore_2
  44. 101: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
  45. 104: iload_2
  46. 105: invokevirtual #7                  // Method java/io/PrintStream.println:(I)V
  47. 108: return

这里我们看到两个字符串都跳到32行,首先跟"righto"比较,如果不相等则跳到47行比较buzzards。

转载于:https://www.cnblogs.com/zhangyfr/p/8493950.html

jdk1.7 String switch的实现相关推荐

  1. JDK1.8 String常量池详解

    jdk 1.8 先抛结论 1.只在常量池上创建常量 2.只在堆上创建对象 3.在堆上创建对象,在常量池上创建常量 4.在堆上创建对象,在常量池上创建引用 注意: 常量池有两种情况:引用(指针) 或 常 ...

  2. switch case穿透Java_Switch语句的case穿透

    Switch语句的case穿透 一 switch语句几点说明: 1. case后面只能是常量,不能是变量,而且,多个case后面的值不能出现相同的. 2.case后面表达式可以接受: 基本数据类型,b ...

  3. Java中switch都可以支持哪些数据类型

    Java中switch都可以支持哪些数据类型 在JDK1.5之前,switch循环只支持byte short char int四种数据类型. JDK1.5 在switch循环中增加了枚举类与byte ...

  4. java的switch参数问题

    switch参数仅支持整数表达式,也可以说是int型,包含int,short,byte,char和枚举(值为int):因为short,byte,char都能自动转换为int型,所以long,Strin ...

  5. Java Switch Statement

    Java Switch Java Switch Statement switch语句的执行规则如下 1.从第一个case开始判断,不匹配则跳到下一个case继续判断: 2.遇到break则跳出swit ...

  6. java 把string转为keyevent_盘点现在Java强大第三方库(字符串操作),程序员都该知道!...

    1.字符串与集合间的转化 引用第三方库 Apache Commons Lang jre连接 值得一提的自JDK1.8以后字符串集合转为字符串可以使用String类下的join()方法,但别的数据类型还 ...

  7. switch case穿透Java_Java switch的用法与case的穿透现象举例详解

    switch和if-else的用法类似: if(x == 3) { }else if(x == 30) { }else if(x == -6) { }else { }等同于switch的: switc ...

  8. swift-switch使用方法

    // Playground - noun: a place where people can playimport UIKit//----------------------------------- ...

  9. java switch小程序,微信小程序 switch组件详解及简单实例

    微信小程序switch 相关文章: 实现效果图: 开关选择器 属性名 类型 默认值 说明 checked Boolean false 是否选中 disabled Boolean false 是否禁用 ...

最新文章

  1. 使用ZFS的十条理由
  2. PHP学习笔记-PHP语言基础1
  3. 修改Android下的radioButton字体的颜色
  4. python逐行读取文件内容的三种方法
  5. 从壹开始 [Admin] 之五 ║ 实现『按钮』级别权限配置
  6. IOS之提示Interface type cannot be statically allocated
  7. JQUERY操作html--获取和设置内容、属性、回调函数
  8. vs2015无法打开包括文件:“winapifamily.h”
  9. 按钮点击没有反应_时控开关按键没反应怎么办?
  10. 【Spark Summit EU 2016】Spark的性能,过去、现在与未来
  11. 仅一年,近半加密货币的“ICO”项目已死
  12. c语言头随机数文件库,C语言随机数使用方法
  13. 光衰高怎么办_灯太亮了怎么办 led灯该如何选择
  14. 关于雨林木风版的linux操作系统ymlf_os_3.0
  15. BZOJ 2429: [HAOI2006]聪明的猴子
  16. Java 应用结构规范
  17. C Primer Plus 第二章 复习题编程练习 答案
  18. Q版京剧脸谱来喽——刀马旦
  19. 访问图片资源403问题
  20. 【Python教程】python之路

热门文章

  1. Python爬虫入门五URLError异常处理
  2. 【Oracle】Python 连接Oracle 数据库
  3. 不要以为学java,.net或VB的就很牛
  4. 深入react技术栈(10):受控组件和非受控组件
  5. 前端学习(2987):vue+element今日头条管理--案例演示
  6. JS中的异步任务有哪些
  7. [html] HTML5的video怎样预加载(支持全量加载)?
  8. [html] 请使用canvas画一个椭圆
  9. [css] 怎么让英文单词的首字母大写?
  10. [vue-cli]vue-cli默认是单页面的,那要弄成多页面该怎么办呢