我们知道在JDK1.6之前 switch语句只支持byte、char、short、int以及Enum,是不支持String类型的
JDK1.7之后加入了对String类型的支持,如下代码(需1.7以上版本):

public class Test {
    public static void main(String[] args) {
        String str = "c";

        switch (str) {
        case "a":
            System.out.println("a");
            break;

        case "b":
            System.out.println("b");
            break;

        case "c":
            System.out.println("c");
            break;
        }
    }
}

原理:JDK1.7在switch语句中可以支持String类型的参数,实际上,

这个新特性是在编译器层次实现的,而在java虚拟机和字节码层次上,还是只支持switch语句中使用与整数类型兼容的类型。


使用javap -c Test 查看编译后的字节码

F:\>javap -c Test
Compiled from "Test.java"
class Test {
  Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String c
       2: astore_1
       3: aload_1
       4: astore_2
       5: iconst_m1
       6: istore_3
       7: aload_2
       8: invokevirtual #3                  // Method java/lang/String.hashCode:    (①)
()I
      11: tableswitch   { // 97 to 99
                    97: 36
                    98: 50
                    99: 64
               default: 75
          }
      36: aload_2
      37: ldc           #4                  // String a
      39: invokevirtual #5                  // Method java/lang/String.equals:(L    (②)
java/lang/Object;)Z
      42: ifeq          75
      45: iconst_0
      46: istore_3
      47: goto          75
      50: aload_2
      51: ldc           #6                  // String b
      53: invokevirtual #5                  // Method java/lang/String.equals:(L
java/lang/Object;)Z
      56: ifeq          75
      59: iconst_1
      60: istore_3
      61: goto          75
      64: aload_2
      65: ldc           #2                  // String c
      67: invokevirtual #5                  // Method java/lang/String.equals:(L
java/lang/Object;)Z
      70: ifeq          75
      73: iconst_2
      74: istore_3
      75: iload_3
      76: tableswitch   { // 0 to 2
                     0: 104
                     1: 115
                     2: 126
               default: 134
          }
     104: getstatic     #7                  // Field java/lang/System.out:Ljava/
io/PrintStream;
     107: ldc           #4                  // String a
     109: invokevirtual #8                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
     112: goto          134
     115: getstatic     #7                  // Field java/lang/System.out:Ljava/
io/PrintStream;
     118: ldc           #6                  // String b
     120: invokevirtual #8                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
     123: goto          134
     126: getstatic     #7                  // Field java/lang/System.out:Ljava/
io/PrintStream;
     129: ldc           #2                  // String c
     131: invokevirtual #8                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
     134: getstatic     #7                  // Field java/lang/System.out:Ljava/
io/PrintStream;
     137: ldc           #9                  // String Hello World!
     139: invokevirtual #8                  // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
     142: return
}

从反编译出来的字节码可以看到,原来用在switch语句中的字符串被替换成了对应的哈希值(第①行),经过这样的转换,java虚拟机所看到的仍然是与整数类型兼容的类型,而case字句对应的语句块仍然需要使用String的equals方法来进行字符串的比较(第②行)。这是因为哈希函数在映射的时候可能存在冲突,多个字符串的哈希值可能是一样的,进行字符串的比较是为了保证转换之后的代码逻辑与之前的完全一样