我们知道在JDK1.6之前 switch语句只支持byte、char、short、int以及Enum,是不支持String类型的
JDK1.7之后加入了对String类型的支持,如下代码(需1.7以上版本):
public class Test
{
public static void main(String[] args)
{
String str = "c";
switch (str) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
case "c":
System.out.println("c");
break;
}
}
}
原理:JDK1.7在switch语句中可以支持String类型的参数,实际上,
这个新特性是在编译器层次实现的,而在java虚拟机和字节码层次上,还是只支持switch语句中使用与整数类型兼容的类型。
使用javap -c Test 查看编译后的字节码
F:/>javap -c Test
Compiled from "Test.java"
class Test {
Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String c
2: astore_1
3: aload_1
4: astore_2
5: iconst_m1
6: istore_3
7: aload_2
8: invokevirtual #3 // Method java/lang/String.hashCode:
()I
11: tableswitch { // 97 to 99
97: 36
98: 50
99: 64
default: 75
}
36: aload_2
37: ldc #4 // String a
39: invokevirtual #5 // Method java/lang/String.equals:(L
java/lang/Object;)Z
42: ifeq 75
45: iconst_0
46: istore_3
47: goto 75
50: aload_2
51: ldc #6 // String b
53: invokevirtual #5 // Method java/lang/String.equals:(L
java/lang/Object;)Z
56: ifeq 75
59: iconst_1
60: istore_3
61: goto 75
64: aload_2
65: ldc #2 // String c
67: invokevirtual #5 // Method java/lang/String.equals:(L
java/lang/Object;)Z
70: ifeq 75
73: iconst_2
74: istore_3
75: iload_3
76: tableswitch { // 0 to 2
0: 104
1: 115
2: 126
default: 134
}
104: getstatic #7 // Field java/lang/System.out:Ljava/
io/PrintStream;
107: ldc #4 // String a
109: invokevirtual #8 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
112: goto 134
115: getstatic #7 // Field java/lang/System.out:Ljava/
io/PrintStream;
118: ldc #6 // String b
120: invokevirtual #8 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
123: goto 134
126: getstatic #7 // Field java/lang/System.out:Ljava/
io/PrintStream;
129: ldc #2 // String c
131: invokevirtual #8 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
134: getstatic #7 // Field java/lang/System.out:Ljava/
io/PrintStream;
137: ldc #9 // String Hello World!
139: invokevirtual #8 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
142: return
}
从反编译出来的字节码可以看到,原来用在switch语句中的字符串被替换成了对应的哈希值(第20行),经过这样的转换,java虚拟机所看到的仍然是与整数类型兼容的类型,而case字句对应的语句块仍然需要使用String的equals方法来进行字符串的比较(第30行)。这是因为哈希函数在映射的时候可能存在冲突,多个字符串的哈希值可能是一样的,进行字符串的比较是为了保证转换之后的代码逻辑与之前的完全一样
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/14183.html