java7(1)——反编译深入理解增强的switch(读字节命令实战)

【本文介绍】

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

  

【正文】

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

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

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

 

 1 public class Test {
 2 
 3     public  void test(String str) {
 4         
 5         switch(str){
 6         
 7         case "a": System.out.println("a");break;
 8         case "b": System.out.println("b");break;
 9         default : System.out.println("default");
10         
11         }
12     }
13 }
View Code

 

(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");
        
        }
    }
}
View Code

 

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

public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
()V
       4: return

  public void test(java.lang.String);
    Code:
       0: aload_1
       1: astore_2                ---------------从这里开始------------
       2: iconst_m1              // 将int型-1推送至栈顶
       3: istore_3               // 赋值,因为此时栈顶元素为-1,所以赋值-1
       4: aload_2
       5: invokevirtual #2                  // Method java/lang/String.hashCode: 调用hasCode方法
()I
       8: lookupswitch  { // 2        源码本来只有一次switch,现在被拆分成两次,这是第一次switch,下面还有一次公共的
                    97: 36           case 97 : 跳至36行 aload_2
                    98: 50           case 98 :跳至50行 aload_2
               default: 61           default : 跳至61行 iload_3
          }
      36: aload_2
      37: ldc           #3                  // String a  下面equal的内容
      39: invokevirtual #4                  // Method java/lang/String.equals:(L  进行equal的比较
java/lang/Object;)Z
      42: ifeq          61           // if 语句
      45: iconst_0               // 将int型0推送至栈顶
      46: istore_3               // 赋值,因为此时栈顶元素为 0 ,所以赋值0
      47: goto          61
      50: aload_2
      51: ldc           #5                  // String b   下面equal的内容
      53: invokevirtual #4                  // Method java/lang/String.equals:(L  进行equal的比较
java/lang/Object;)Z
      56: ifeq          61           // if 语句
      59: iconst_1               // 将int型1推送至栈顶 
      60: istore_3               // 赋值,因为此时栈顶元素为 1 , 所以赋值1
      61: iload_3                ----------------到这里结束---------------
      62: lookupswitch  { // 2
                     0: 88
                     1: 99
               default: 110
          }
      88: getstatic     #6                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      91: ldc           #3                  // String a
      93: invokevirtual #7                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      96: goto          118
      99: getstatic     #6                  // Field java/lang/System.out:Ljava/
io/PrintStream;
     102: ldc           #5                  // String b
     104: invokevirtual #7                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
     107: goto          118
     110: getstatic     #6                  // Field java/lang/System.out:Ljava/
io/PrintStream;
     113: ldc           #8                  // String default
     115: invokevirtual #7                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
     118: return
}
View Code

 

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

public class Test2 {
  public Test2();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
()V
       4: return

  public void test(int);
    Code:
       0: iload_1
       1: lookupswitch  { // 2
                     1: 28
                     2: 39
               default: 50
          }
      28: getstatic     #2                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      31: ldc           #3                  // String 1
      33: invokevirtual #4                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      36: goto          58
      39: getstatic     #2                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      42: ldc           #5                  // String 2
      44: invokevirtual #4                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      47: goto          58
      50: getstatic     #2                  // Field java/lang/System.out:Ljava/
io/PrintStream;
      53: ldc           #6                  // String default
      55: invokevirtual #4                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
      58: return
}
View Code

 

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

(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 }
View Code
posted @ 2014-08-01 23:14  小M的博客  阅读(664)  评论(0编辑  收藏  举报