jdk1.7 String switch的实现
对于int的switch,jvm是用tableswitch和lookupswitch来实现的,jdk1.7 switch增加了对string的支持,那么底层是如何实现的呢?是否增加了新的指令或是否给某些指令增加了新的含义?
看这样一个程序:
![](http://freish.iteye.com/images/icon_star.png)
- public class Test {
- public static void main(String[] args) {
- String name = "b";
- int value = 0;
- switch(name) {
- case "a":
- value = 1;
- break;
- case "b":
- value = 2;
- break;
- case "c":
- value = 3;
- break;
- case "d":
- value = 4;
- break;
- case "e":
- value = 5;
- break;
- default:
- value = 6;
- }
- System.out.println(value);
- }
- }
javap -c Test得出的结果为:
![](http://freish.iteye.com/images/icon_star.png)
- public static void main(java.lang.String[]);
- Code:
- 0: ldc #2 // String b
- 2: astore_1 //将"b"赋值给name
- 3: iconst_0 //将0入栈
- 4: istore_2 //将0赋值给value
- 5: aload_1 //将name(即"b")入栈
- 6: astore_3 //将name(即"b")赋值给一个编译器生成的变量,记为tmpName(tmpName此时也是"b")
- 7: iconst_m1 //将-1入栈
- 8: istore 4 //将-1赋值给一个编译器生成的变量,记为m1
- 10: aload_3 //将tmpName(即"b")入栈
- 11: invokevirtual #3 // Method java/lang/String.hashCode:()I 调用tmpName的hashCode方法("b".hashCode(),得结果98)
- 14: tableswitch { // 97 to 101 //根据hashCode的值到不同的分支
- 97: 48
- 98: 63 //这里走到这个分支,跳转到63
- 99: 78
- 100: 93
- 101: 108
- default: 120
- }
- 48: aload_3
- 49: ldc #4 // String a
- 51: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
- 54: ifeq 120
- 57: iconst_0
- 58: istore 4
- 60: goto 120
- 63: aload_3 //从14跳转到了这里,将tmpName(即"b")入栈
- 64: ldc #2 // String b 将"b"入栈
- 66: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
- //比较tmpName和"b",如果相等,将1入栈,不等将0入栈.这里是相等的,入栈的为1
- 69: ifeq 120 //从栈顶取出比较结果,如果等于0,就跳到120,如果不等于0就继续下面的指令,这里显然不等于0
- 72: iconst_1 //将1入栈
- 73: istore 4 //将1存储到m1中
- 75: goto 120 //跳到120
- 78: aload_3
- 79: ldc #6 // String c
- 81: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
- 84: ifeq 120
- 87: iconst_2
- 88: istore 4
- 90: goto 120
- 93: aload_3
- 94: ldc #7 // String d
- 96: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
- 99: ifeq 120
- 102: iconst_3
- 103: istore 4
- 105: goto 120
- 108: aload_3
- 109: ldc #8 // String e
- 111: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
- 114: ifeq 120
- 117: iconst_4
- 118: istore 4
- 120: iload 4 //将m1(即73行存进去的1)的值入栈
- 122: tableswitch { // 0 to 4
- 0: 156
- 1: 161 //这里走1这个分支,跳到161
- 2: 166
- 3: 171
- 4: 176
- default: 181
- }
- 156: iconst_1
- 157: istore_2
- 158: goto 184
- 161: iconst_2 //将2入栈
- 162: istore_2 //将2存储到value
- 163: goto 184 //跳转到184进行打印输出
- 166: iconst_3
- 167: istore_2
- 168: goto 184
- 171: iconst_4
- 172: istore_2
- 173: goto 184
- 176: iconst_5
- 177: istore_2
- 178: goto 184
- 181: bipush 6
- 183: istore_2
- 184: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
- 187: iload_2
- 188: invokevirtual #10 // Method java/io/PrintStream.println:(I)V
- 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
![](http://freish.iteye.com/images/icon_star.png)
- public class Test {
- public static void main(String[] args) {
- String name = "buzzards";
- int value = 0;
- switch(name) {
- case "buzzards":
- value = 1;
- break;
- case "righto":
- value = 2;
- break;
- default:
- value = 6;
- }
- System.out.println(value);
- }
- }
字节码:
![](http://freish.iteye.com/images/icon_star.png)
- public static void main(java.lang.String[]);
- Code:
- 0: ldc #2 // String buzzards
- 2: astore_1
- 3: iconst_0
- 4: istore_2
- 5: aload_1
- 6: astore_3
- 7: iconst_m1
- 8: istore 4
- 10: aload_3
- 11: invokevirtual #3 // Method java/lang/String.hashCode:()I
- 14: lookupswitch { // 1
- -931102253: 32
- default: 59
- }
- 32: aload_3
- 33: ldc #4 // String righto
- 35: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)
- 38: ifeq 47
- 41: iconst_1
- 42: istore 4
- 44: goto 59
- 47: aload_3
- 48: ldc #2 // String buzzards
- 50: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)
- 53: ifeq 59
- 56: iconst_0
- 57: istore 4
- 59: iload 4
- 61: lookupswitch { // 2
- 0: 88
- 1: 93
- default: 98
- }
- 88: iconst_1
- 89: istore_2
- 90: goto 101
- 93: iconst_2
- 94: istore_2
- 95: goto 101
- 98: bipush 6
- 100: istore_2
- 101: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
- 104: iload_2
- 105: invokevirtual #7 // Method java/io/PrintStream.println:(I)V
- 108: return
这里我们看到两个字符串都跳到32行,首先跟"righto"比较,如果不相等则跳到47行比较buzzards。
转载于:https://www.cnblogs.com/zhangyfr/p/8493950.html
jdk1.7 String switch的实现相关推荐
- JDK1.8 String常量池详解
jdk 1.8 先抛结论 1.只在常量池上创建常量 2.只在堆上创建对象 3.在堆上创建对象,在常量池上创建常量 4.在堆上创建对象,在常量池上创建引用 注意: 常量池有两种情况:引用(指针) 或 常 ...
- switch case穿透Java_Switch语句的case穿透
Switch语句的case穿透 一 switch语句几点说明: 1. case后面只能是常量,不能是变量,而且,多个case后面的值不能出现相同的. 2.case后面表达式可以接受: 基本数据类型,b ...
- Java中switch都可以支持哪些数据类型
Java中switch都可以支持哪些数据类型 在JDK1.5之前,switch循环只支持byte short char int四种数据类型. JDK1.5 在switch循环中增加了枚举类与byte ...
- java的switch参数问题
switch参数仅支持整数表达式,也可以说是int型,包含int,short,byte,char和枚举(值为int):因为short,byte,char都能自动转换为int型,所以long,Strin ...
- Java Switch Statement
Java Switch Java Switch Statement switch语句的执行规则如下 1.从第一个case开始判断,不匹配则跳到下一个case继续判断: 2.遇到break则跳出swit ...
- java 把string转为keyevent_盘点现在Java强大第三方库(字符串操作),程序员都该知道!...
1.字符串与集合间的转化 引用第三方库 Apache Commons Lang jre连接 值得一提的自JDK1.8以后字符串集合转为字符串可以使用String类下的join()方法,但别的数据类型还 ...
- switch case穿透Java_Java switch的用法与case的穿透现象举例详解
switch和if-else的用法类似: if(x == 3) { }else if(x == 30) { }else if(x == -6) { }else { }等同于switch的: switc ...
- swift-switch使用方法
// Playground - noun: a place where people can playimport UIKit//----------------------------------- ...
- java switch小程序,微信小程序 switch组件详解及简单实例
微信小程序switch 相关文章: 实现效果图: 开关选择器 属性名 类型 默认值 说明 checked Boolean false 是否选中 disabled Boolean false 是否禁用 ...
最新文章
- 使用ZFS的十条理由
- PHP学习笔记-PHP语言基础1
- 修改Android下的radioButton字体的颜色
- python逐行读取文件内容的三种方法
- 从壹开始 [Admin] 之五 ║ 实现『按钮』级别权限配置
- IOS之提示Interface type cannot be statically allocated
- JQUERY操作html--获取和设置内容、属性、回调函数
- vs2015无法打开包括文件:“winapifamily.h”
- 按钮点击没有反应_时控开关按键没反应怎么办?
- 【Spark Summit EU 2016】Spark的性能,过去、现在与未来
- 仅一年,近半加密货币的“ICO”项目已死
- c语言头随机数文件库,C语言随机数使用方法
- 光衰高怎么办_灯太亮了怎么办 led灯该如何选择
- 关于雨林木风版的linux操作系统ymlf_os_3.0
- BZOJ 2429: [HAOI2006]聪明的猴子
- Java 应用结构规范
- C Primer Plus 第二章 复习题编程练习 答案
- Q版京剧脸谱来喽——刀马旦
- 访问图片资源403问题
- 【Python教程】python之路
热门文章
- Python爬虫入门五URLError异常处理
- 【Oracle】Python 连接Oracle 数据库
- 不要以为学java,.net或VB的就很牛
- 深入react技术栈(10):受控组件和非受控组件
- 前端学习(2987):vue+element今日头条管理--案例演示
- JS中的异步任务有哪些
- [html] HTML5的video怎样预加载(支持全量加载)?
- [html] 请使用canvas画一个椭圆
- [css] 怎么让英文单词的首字母大写?
- [vue-cli]vue-cli默认是单页面的,那要弄成多页面该怎么办呢