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上並無進行修改。
相關文章
相關標籤/搜索