java switch語句探索

1、問題

對於下面的代碼:

public class Switch{
	public void test(int i) {
		switch(i) {
			case 0:
			case 1:
				System.out.println("a");
				break;
			case 2:
				System.out.println("a");
				break;
			default:
				break;
		}
	}
}
我們會發現,當i=0的時候,會進入0的case塊,並且還繼續執行1的case塊;當i=2的時候只執行2的case塊;當i=3的時候直接執行的是default的case塊。很多時候我們不知道這其中的原因是什麼,下面就是筆者帶領大家深入理解這些東西背後的深層次的原因。

2、反編譯上面的代碼:

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

  public void test(int);
    Code:
       0: iload_1       
       1: tableswitch   { // 0 to 4
                     0: 36
                     1: 36
                     2: 58
                     3: 69
                     4: 47
               default: 69
          }
      36: getstatic     #2;                 // Field java/lang/System.out:Ljava/io/PrintStream;
      39: ldc           #3;                 // String a
      41: invokevirtual #4;                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      44: goto          69
      47: getstatic     #2;                 // Field java/lang/System.out:Ljava/io/PrintStream;
      50: ldc           #5;                 // String c
      52: invokevirtual #4;                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      55: goto          69
      58: getstatic     #2;                 // Field java/lang/System.out:Ljava/io/PrintStream;
      61: ldc           #3;                 // String a
      63: invokevirtual #4;                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: goto          69
      69: return        
}



我們只關注test方法,Code後面的都是反編譯出來的字節碼,其中每行的開始是字節碼在每一個代碼塊的開始的字節,所以這些數字不會是連續的,爲了方便,筆者下面只稱這些字節索引值爲行。

0行:將本地方法棧的第一個局部加載到操作棧中,第一個參數就是test的方法的參數i,可能有讀者會問,那test方法的本地方法棧的第0個局部變量是什麼?對於非static的方法,編譯器會給方法的插入一個默認的參數,這個參數指向類的實例,其實也就是所謂的this對象,這就是爲什麼我們在static方法中沒有辦法使用this,而只能在非static方法中使用的緣故。

1行:在表中查找實際的i值對應的實際的代碼入口,從這個代碼查找我們可以發現i=0和i=1的時候指向了相同的代碼入口,i=2時指向了case 2的代碼的入口

36行到69行:我們發現swicth-case語句中的所有的非case語句,都編譯到了一起,只有遇到像44行、55行這樣的break語句纔會跳出,也就是說,如果沒有,就會繼續往下走,所以說,像下面的語句,遇到case A,會執行do_a也會執行do_b。

case A:
 do_a
case B:
 do_b;
 break;

3、還有一些關於tableswitch的其他東西,比如排序等等,還有稀疏的case情況的處理,以及java 7支持的string的swicth-case,等明天再寫,困死了,洗洗睡覺。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章