对于int的switch,jvm是用tableswitch和lookupswitch来实现的,jdk1.7 switch增加了对string的支持,那么底层是如何实现的呢?是否增加了新的指令或是否给某些指令增加了新的含义?
看这样一个程序:
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得出的结果为:
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
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);
}
}
字节码:
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。
相关推荐
JDK1.7新特性介绍 1. 对Java集合(Collections)的增强支持 2. 在Switch中可用String 在JDK7 的正式版本中,你可以在switch的表达式中用String类型 3. 数值可加下划线 下划线字符(_)能够出现在数字字面量的数字...
JDK1.7新特性介绍 1. 对Java集合(Collections)的增强支持 2. 在Switch中可用String 3. 数值可加下划线 4. 支持二进制文字 5. 简化了可变参数方法的调用 ....
jdk1.7 仅包含macos 系统支持的dmg jdk1.7新特性 1 对集合类的语言支持; 2 自动资源管理; 3 改进的通用实例创建类型推断;...5 switch中使用string; 6 二进制字面量; 7 简化可变参数方法调用。
jdk1.7jdk17新特性详解 二进制字面量 在数字字面量使用下划线 switch可以使用string了 实例创建的类型推断 使用Varargs方法使用不可维护的形式参数时改进了编译器警告和错误 try-with-resources 资源的自动管理 捕捉...
自动资源管理;改进的通用实例创建类型推断; 数字字面量下划线支持; switch中使用string; 二进制字面量; 简化可变参数方法调用;
在JDK1.7中,摒弃了Java集合接口的实现类,如:ArrayList、HashSet和HashMap。而是直接采用[]、{}的形式存入对象,采用[]的形式按照索引、键值来获取集合中的对象,如下: List<String> list = ["item"]; // 向List...
jdk1.7新特性 1 对集合类的语言支持; 2 自动资源管理; 3 改进的通用实例创建类型推断; 4 数字字面量下划线支持; 5 switch中使用string; 6 二进制字面量; 7 简化可变参数方法调用
jdk1.7新特性 1 对集合类的语言支持; 2 自动资源管理; 3 改进的通用实例创建类型推断; 4 数字字面量下划线支持; 5 switch中使用string; 6 二进制字面量; 7 简化可变参数方法调用。
jdk1.7新特性 1 对集合类的语言支持; 2 自动资源管理; 3 改进的通用实例创建类型推断; 4 数字字面量下划线支持; 5 switch中使用string; 6 二进制字面量; 7 简化可变参数方法调用。
jdk1.7新特性 1 对集合类的语言支持; 2 自动资源管理; 3 改进的通用实例创建类型推断; 4 数字字面量下划线支持; 5 switch中使用string; 6 二进制字面量; 7 简化可变参数方法调用。
jdk1.7的新特性主要内容: 在switch中使用String,在1.7以前只支持byte,short,int,char,enum。使用方式和使用byte,short那些一样,就不举例子了。 try-with-resources,之前使用的很多IO操作都需要手动去关闭流,...
jdk1.7新特性 jdk1.8新特性 java语言有哪些优点? 同一个.java文件中是否可以有多个main方法 一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 如何在main方法执行前输出”hello world” java程序...
mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包。这些软件工具均可以到各自的官方网站上下载。 首先建立一个名字为 MyBaits 的 dynamic web project 1. 现阶段,你可以...
9.3.2 String、StringBuffer和StringBuilder类 322 9.3.3 Math类 327 9.3.4 Random类 328 9.3.5 BigDecimal类 330 9.4 处理日期的类 333 9.4.1 Date类 333 9.4.2 Calendar类 334 9.4.3 TimeZone类 337 9.5 ...
基本信息 作者: 臧萌 ...12.2.4 使用接口仅需一步——实现接口 342 12.2.5 接口——让类集多重类型于一身 344 12.2.6 简化recordTransport()方法 347 12.3 再探接口 349 12.3.1 重温上节中的程序 349...
基本信息 作者: 臧萌 ...12.2.4 使用接口仅需一步——实现接口 342 12.2.5 接口——让类集多重类型于一身 344 12.2.6 简化recordTransport()方法 347 12.3 再探接口 349 12.3.1 重温上节中的程序 349...