首页 > 代码库 > java7(1)——反编译深入理解增强的switch

java7(1)——反编译深入理解增强的switch

【本文介绍】

  本文主要讲java_7 的改进switch的底层实现。反编译一个使用带String的switch的demo并一步步解析反编译出来的字节码,从编译的角度解读switch的底层实现。

  

【正文】

  在java7中,switch()可以放进去String 类型了,这无非是一大便利。底层JVM的swtich并没有真正的改进,只是在编译阶段,编译器把关于String的switch拆分成if语句而已。

  我们写一个简单的例子测试一下:

(1)Test类:switch()使用String

public class Test {    public  void test(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 class Test2 {    public  void test(int str) {                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 class Test { 2   public Test(); 3     Code: 4        0: aload_0 5        1: invokespecial #1                  // Method java/lang/Object."<init>": 6 ()V 7        4: return 8  9   public void test(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_220                     98: 50           case 98 :跳至50行 aload_221                default: 61           default : 跳至61行 iload_322           }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          6131       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  { // 240                      0: 8841                      1: 9942                default: 11043           }44       88: getstatic     #6                  // Field java/lang/System.out:Ljava/45 io/PrintStream;46       91: ldc           #3                  // String a47       93: invokevirtual #7                  // Method java/io/PrintStream.printl48 n:(Ljava/lang/String;)V49       96: goto          11850       99: getstatic     #6                  // Field java/lang/System.out:Ljava/51 io/PrintStream;52      102: ldc           #5                  // String b53      104: invokevirtual #7                  // Method java/io/PrintStream.printl54 n:(Ljava/lang/String;)V55      107: goto          11856      110: getstatic     #6                  // Field java/lang/System.out:Ljava/57 io/PrintStream;58      113: ldc           #8                  // String default59      115: invokevirtual #7                  // Method java/io/PrintStream.printl60 n:(Ljava/lang/String;)V61      118: return62 }

 

javac 编译 , javap -c 反编译 Test2 后的结果:

 1 public class Test2 { 2   public Test2(); 3     Code: 4        0: aload_0 5        1: invokespecial #1                  // Method java/lang/Object."<init>": 6 ()V 7        4: return 8  9   public void test(int);10     Code:11        0: iload_112        1: lookupswitch  { // 213                      1: 2814                      2: 3915                default: 5016           }17       28: getstatic     #2                  // Field java/lang/System.out:Ljava/18 io/PrintStream;19       31: ldc           #3                  // String 120       33: invokevirtual #4                  // Method java/io/PrintStream.printl21 n:(Ljava/lang/String;)V22       36: goto          5823       39: getstatic     #2                  // Field java/lang/System.out:Ljava/24 io/PrintStream;25       42: ldc           #5                  // String 226       44: invokevirtual #4                  // Method java/io/PrintStream.printl27 n:(Ljava/lang/String;)V28       47: goto          5829       50: getstatic     #2                  // Field java/lang/System.out:Ljava/30 io/PrintStream;31       53: ldc           #6                  // String default32       55: invokevirtual #4                  // Method java/io/PrintStream.printl33 n:(Ljava/lang/String;)V34       58: return35 }

  大家看到这么多字节码是不是有点头晕不想再看下去了?其实只需稍稍观察比较就能发现”从这里开始“——”到这里结束“中间那些字节码是下面那个字节码文件所没有的,所以我们研究这几行代码就行了。又看我用红色字体标出来的注释,结果就显而易见了:

(0)用一个int类型变量代表String类型变量

(1)获取String字符串的hashCode

(2)case hashCode

(3)用if语句处理String

(4)为int类型的变量赋值

(5)真正的swtich,现在传入的是上面得出的int类型变量。

把上面的字节码文件翻译成java即:

 1 public class test { 2  3     public void test(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 }