JDK1.7 switch支持String类型的原理详解编程语言

我们知道在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语句中的字符串被替换成了对应的哈希值(第20行),经过这样的转换,java虚拟机所看到的仍然是与整数类型兼容的类型,而case字句对应的语句块仍然需要使用String的equals方法来进行字符串的比较(第30行)。这是因为哈希函数在映射的时候可能存在冲突,多个字符串的哈希值可能是一样的,进行字符串的比较是为了保证转换之后的代码逻辑与之前的完全一样

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/14183.html

(0)
上一篇 2021年7月19日 16:38
下一篇 2021年7月19日 16:38

相关推荐

发表回复

登录后才能评论