【本文介绍】
本文主要讲java_7 的改进switch的底层实现。反编译一个使用带String的switch的demo并一步步解析反编译出来的字节码,从编译的角度解读switch的底层实现。
【正文】
在java7中,switch()可以放进去String 类型了,这无非是一大便利。底层JVM的swtich并没有真正的改进,只是在编译阶段,编译器把关于String的switch拆分成if语句而已。
我们写一个简单的例子测试一下:
(1)Test类:switch()使用String
public classTest {public voidtest(String str) {switch(str){case "a": System.out.println("a");break;case "b": System.out.println("b");break;default : System.out.println("default");
}
}
}
(2)Test2类:switch()使用int
public classTest2 {public void test(intstr) {switch(str){case 1: System.out.println("1");break;case 2: System.out.println("2");break;default : System.out.println("default");
}
}
}
javac 编译 , javap -c 反编译 Test 后的结果:
1 public classTest {2 publicTest();3 Code:4 0: aload_05 1: invokespecial #1 //Method java/lang/Object."":
6 ()V7 4: return
8
9 public voidtest(java.lang.String);10 Code:11 0: aload_112 1: astore_2 ---------------从这里开始------------13 2: iconst_m1 // 将int型-1推送至栈顶14 3: istore_3 // 赋值,因为此时栈顶元素为-1,所以赋值-115 4: aload_216 5: invokevirtual #2 //Method java/lang/String.hashCode: 调用hasCode方法
17 ()I18 8: lookupswitch { //2 源码本来只有一次switch,现在被拆分成两次,这是第一次switch,下面还有一次公共的
19 97: 36 case 97 : 跳至36行 aload_2
20 98: 50 case 98 :跳至50行 aload_2
21 default: 61 default : 跳至61行 iload_3
22 }23 36: aload_224 37: ldc #3 //String a 下面equal的内容
25 39: invokevirtual #4 // Method java/lang/String.equals:(L 进行equal的比较
26 java/lang/Object;)Z27 42: ifeq 61 // if 语句
28 45: iconst_0 // 将int型0推送至栈顶29 46: istore_3 // 赋值,因为此时栈顶元素为 0 ,所以赋值030 47: goto 61
31 50: aload_232 51: ldc #5 //String b 下面equal的内容
33 53: invokevirtual #4 // Method java/lang/String.equals:(L进行equal的比较
34 java/lang/Object;)Z35 56: ifeq 61 // if 语句
36 59: iconst_1 // 将int型1推送至栈顶37 60: istore_3 // 赋值,因为此时栈顶元素为 1 , 所以赋值138 61: iload_3 ----------------到这里结束---------------39 62: lookupswitch { //2
40 0: 88
41 1: 99
42 default: 110
43 }44 88: getstatic #6 //Field java/lang/System.out:Ljava/
45 io/PrintStream;46 91: ldc #3 //String a
47 93: invokevirtual #7 //Method java/io/PrintStream.printl
48 n:(Ljava/lang/String;)V49 96: goto 118
50 99: getstatic #6 //Field java/lang/System.out:Ljava/
51 io/PrintStream;52 102: ldc #5 //String b
53 104: invokevirtual #7 //Method java/io/PrintStream.printl
54 n:(Ljava/lang/String;)V55 107: goto 118
56 110: getstatic #6 //Field java/lang/System.out:Ljava/
57 io/PrintStream;58 113: ldc #8 //String default
59 115: invokevirtual #7 //Method java/io/PrintStream.printl
60 n:(Ljava/lang/String;)V61 118: return
62 }
javac 编译 , javap -c 反编译 Test2 后的结果:
1 public classTest2 {2 publicTest2();3 Code:4 0: aload_05 1: invokespecial #1 //Method java/lang/Object."":
6 ()V7 4: return
8
9 public void test(int);10 Code:11 0: iload_112 1: lookupswitch { //2
13 1: 28
14 2: 39
15 default: 50
16 }17 28: getstatic #2 //Field java/lang/System.out:Ljava/
18 io/PrintStream;19 31: ldc #3 //String 1
20 33: invokevirtual #4 //Method java/io/PrintStream.printl
21 n:(Ljava/lang/String;)V22 36: goto 58
23 39: getstatic #2 //Field java/lang/System.out:Ljava/
24 io/PrintStream;25 42: ldc #5 //String 2
26 44: invokevirtual #4 //Method java/io/PrintStream.printl
27 n:(Ljava/lang/String;)V28 47: goto 58
29 50: getstatic #2 //Field java/lang/System.out:Ljava/
30 io/PrintStream;31 53: ldc #6 //String default
32 55: invokevirtual #4 //Method java/io/PrintStream.printl
33 n:(Ljava/lang/String;)V34 58: return
35 }
大家看到这么多字节码是不是有点头晕不想再看下去了?其实只需稍稍观察比较就能发现”从这里开始“——”到这里结束“中间那些字节码是下面那个字节码文件所没有的,所以我们研究这几行代码就行了。又看我用红色字体标出来的注释,结果就显而易见了:
(0)用一个int类型变量代表String类型变量
(1)获取String字符串的hashCode
(2)case hashCode
(3)用if语句处理String
(4)为int类型的变量赋值
(5)真正的swtich,现在传入的是上面得出的int类型变量。
把上面的字节码文件翻译成java即:
1 public classtest {2
3 public voidtest(String str) {4
5 int i = -1;6
7 switch(str.hashCode()){8
9 case 97:10 if(str.equals("a")){11 i = 0;12 }13 break;14 case 98:15 if(str.equals("b")){16 break;17 }18 }19
20 switch(i) {21
22 case 0:23 System.out.println("a");24 break;25
26 case 1:27 System.out.println("b");28 break;29
30 default:31 System.out.println("default");32 }33 }34 }
原文:http://www.cnblogs.com/xiaoMzjm/p/3885990.html