Java jre7及以上版本中的switch支持String的實現細節


Java7中的switch支持String的實現細節

 

在Java7之前,switch只能支持 byte、short、char、int或者其對應的封裝類以及Enum類型。在Java7中,呼吁很久的String支持也終於被加上了。
 
例如,下面是一段switch中使用String的示例代碼。
 
 1 public class Test {
 2 
 3     public void test(String str) {
 4         switch(str) {
 5         case "abc":
 6             System.out.println("abc");
 7             break;
 8         case "def":
 9             System.out.println("def");
10             break;
11         default:
12             System.out.println("default");
13         }
14     }
15 
16 }

 

 
 
在switch語句中,String的比較用的是String.equals,因此大家可以放心的使用。
需要注意的是,傳給switch的String變量不能為null,同時switch的case子句中使用的字符串也不能為null。
為什么要有這些非null的限制呢?其實,我們只要將這段代碼反匯編出來,看一下底層到底是如何實現的,就可以明白了。下面是匯編出來的代碼。
 
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
  Code:
   0:     aload_0
   1:     invokespecial     #1; //Method java/lang/Object."":()V
   4:     return
 
public void test(java.lang.String);
  Code:
   0:     aload_1
   1:     astore_2
   2:     iconst_m1
   3:     istore_3
   4:     aload_2
   5:     invokevirtual     #2; //Method java/lang/String.hashCode:()I
   8:     lookupswitch{ //2
          96354: 36;
          99333: 50;
          default: 61 }
   36:     aload_2
   37:     ldc     #3; //String abc
   39:     invokevirtual     #4; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
   42:     ifeq     61
   45:     iconst_0
   46:     istore_3
   47:     goto     61
   50:     aload_2
   51:     ldc     #5; //String def
   53:     invokevirtual     #4; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
   56:     ifeq     61
   59:     iconst_1
   60:     istore_3
   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 abc
   93:     invokevirtual     #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   96:     goto     118
   99:     getstatic     #6; //Field java/lang/System.out:Ljava/io/PrintStream;
   102:     ldc     #5; //String def
   104:     invokevirtual     #7; //Method java/io/PrintStream.println:(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.println:(Ljava/lang/String;)V
   118:     return
 
}
 
估計有些同學懶得看這些匯編,其實把上面的匯編代碼用Java寫出來就是下面的樣子了。
寫到這里,大家應該能明白為什么不能用null了吧。
 
 1 public class Test {
 2     public void test(String str) {
 3         int i = -1;
 4         switch(str.hashCode()) {
 5         case 96354: // "abc".hashCode()
 6             if (str.equals("abc")) {
 7               i = 0;
 8             }
 9             break;
10         case 99333: // "def".hashCode()
11             if (str.equals("def")) {
12               i = 1;
13             }
14             break;
15         default:
16             break;
17         }
18 
19         switch(i) {
20         case 0:
21             System.out.println("abc");
22             break;
23         case 1:
24             System.out.println("def");
25             break;
26         default:
27             System.out.println("default");
28         }
29     }
30 }

 

 
如果switch傳入的null,那么在運行時對一個null對象調用hashCode方法會出現NullPointerException。
如果switch的case寫的是null,那么在編譯時無法求出hashCode,因此在編譯時就會報錯了。
 
switch支持String只是一個語法糖,由javac來負責生成相應的代碼。底層的JVM在switch上並沒有進行修改。
 
參考
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
 
如果switch傳入的null,那么在運行時對一個null對象調用hashCode方法會出現NullPointerException。
如果switch的case寫的是null,那么在編譯時無法求出hashCode,因此在編譯時就會報錯了。
 
switch支持String只是一個語法糖,由javac來負責生成相應的代碼。底層的JVM在switch上並沒有進行修改。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM