前言
大家都知道,从JDK 1.7开始,switch表达式开始支持String字符串,那么它是怎么实现的呢?
今天来一探究竟
分析
首先写一个小demo,如下所示,一个简单的switc语句:
public class test {
public static void main(String[] args) {
test("a");
}
public static void test(String s) {
switch (s) {
case "a":
System.out.println("hello");
break;
case "b":
System.out.println("world");
break;
default:
}
}
}
然后执行javap -c test.class命令,查看其汇编指令执行过程:
public class test {
public 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 a
2: invokestatic #3 // Method test:(Ljava/lang/String;)V
5: return
public static void test(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #4 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
97: 36
98: 50
default: 61
}
36: aload_1
37: ldc #2 // String a
39: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_2
47: goto 61
50: aload_1
51: ldc #6 // String b
53: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_2
61: iload_2
62: lookupswitch { // 2
0: 88
1: 99
default: 110
}
88: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #8 // String hello
93: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 110
99: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #10 // String world
104: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 110
110: return
}
可以看出,对String对象调用了hashCode()方法,得到了一个int类型的hash值,然后用这个hash值来唯一标识这个case。
所以当匹配时:
- 首先调用这个字符串的hashCode()方法,获取一个hash值(int 类型),用这个hash值来匹配所有的case;
- 如果没有匹配成功,说明不存在;
- 如果匹配成功了,接着会调用字符串的equals()方法进行匹配。
注意:switch的case子句中使用的字符串也不能为null。
小结
从本质上讲,switch对字符串的支持,其实是int类型值的匹配。