您的位置:首页 > 编程语言 > Java开发

jdk1.7 String switch的实现

2013-08-07 14:48 162 查看
参考:http://freish.iteye.com/blog/1152921

对于int的switch,jvm是用tableswitch和lookupswitch来实现的,jdk1.7 switch增加了对string的支持,那么底层是如何实现的呢?是否增加了新的指令或是否给某些指令增加了新的含义?

看这样一个程序:

 

Java代码  


public class Test {     

    public static void main(String[] args) {    

        String name = "b";  

        int value = 0;  

        switch(name) {  

            case "a":  

                value = 1;  

                break;  

            case "b":  

                value = 2;  

                break;  

            case "c":  

                value = 3;  

                break;  

            case "d":  

                value = 4;  

                break;  

            case "e":  

                value = 5;  

                break;  

            default:  

                value = 6;  

        }  

        System.out.println(value);  

    }    

}  

 

javap -c Test得出的结果为:

 

 

Java代码  


public static void main(java.lang.String[]);  

  Code:  

     0: ldc           #2                  // String b  

     2: astore_1                    //将"b"赋值给name  

     3: iconst_0                    //将0入栈  

     4: istore_2                    //将0赋值给value  

     5: aload_1                 //将name(即"b")入栈  

     6: astore_3                    //将name(即"b")赋值给一个编译器生成的变量,记为tmpName(tmpName此时也是"b")  

     7: iconst_m1                   //将-1入栈  

     8: istore        4         //将-1赋值给一个编译器生成的变量,记为m1  

    10: aload_3                 //将tmpName(即"b")入栈  

    11: invokevirtual #3                  // Method java/lang/String.hashCode:()I       调用tmpName的hashCode方法("b".hashCode(),得结果98)  

    14: tableswitch   { // 97 to 101        //根据hashCode的值到不同的分支  

                  97: 48  

                  98: 63                    //这里走到这个分支,跳转到63  

                  99: 78  

                 100: 93  

                 101: 108  

             default: 120  

        }  

    48: aload_3  

    49: ldc           #4                  // String a  

    51: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  

    54: ifeq          120  

    57: iconst_0  

    58: istore        4  

    60: goto          120  

    63: aload_3                         //从14跳转到了这里,将tmpName(即"b")入栈  

    64: ldc           #2                  // String b       将"b"入栈  

    66: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z     

                                    //比较tmpName和"b",如果相等,将1入栈,不等将0入栈.这里是相等的,入栈的为1  

    69: ifeq          120                   //从栈顶取出比较结果,如果等于0,就跳到120,如果不等于0就继续下面的指令,这里显然不等于0  

    72: iconst_1                            //将1入栈  

    73: istore        4                 //将1存储到m1中  

    75: goto          120                   //跳到120  

    78: aload_3  

    79: ldc           #6                  // String c  

    81: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  

    84: ifeq          120  

    87: iconst_2  

    88: istore        4  

    90: goto          120  

    93: aload_3  

    94: ldc           #7                  // String d  

    96: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  

    99: ifeq          120  

   102: iconst_3  

   103: istore        4  

   105: goto          120  

   108: aload_3  

   109: ldc           #8                  // String e  

   111: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  

   114: ifeq          120  

   117: iconst_4  

   118: istore        4  

   120: iload         4                 //将m1(即73行存进去的1)的值入栈  

   122: tableswitch   { // 0 to 4             

                   0: 156  

                   1: 161                   //这里走1这个分支,跳到161  

                   2: 166  

                   3: 171  

                   4: 176  

             default: 181  

        }  

   156: iconst_1  

   157: istore_2  

   158: goto          184  

   161: iconst_2                    //将2入栈  

   162: istore_2                    //将2存储到value  

   163: goto          184           //跳转到184进行打印输出  

   166: iconst_3  

   167: istore_2  

   168: goto          184  

   171: iconst_4  

   172: istore_2  

   173: goto          184  

   176: iconst_5  

   177: istore_2  

   178: goto          184  

   181: bipush        6  

   183: istore_2  

   184: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;  

   187: iload_2  

   188: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V  

   191: return  

 

 

在这一堆指令中我们发现,jdk1.7并没有新指令来处理string switch,还是继续用lookupswitch和tableswitch两个指令来处理的,也没有扩展这两个指令,它们还是只能处理int。

 

 

在11行,我们看到调用了需要switch的string的hashCode方法,并对该hashCode进行switch,并跳转到相应的处理指令。跳到新的指令处我们发现这里(63行)将待switch的变量(name)与case中的值("b")equals了一下。这样做是为了避免不同的string有相同的hashCode,确定equals返回true后,编译器生成了一个处理value的switch,源码里有多少个case编译器生成的tableswitch就有多少个分支,最终会找到相应的处理分支完成string switch的处理。

 

 

接下来,看一个不同string hashCode相等的版本:

 

buzzards与righto的hashCode相等

hierarch与crinolines的hashCode相等

 

这里选择buzzards和righto

 

 

Java代码  


public class Test {     

    public static void main(String[] args) {    

        String name = "buzzards";  

        int value = 0;  

        switch(name) {  

            case "buzzards":  

                value = 1;  

                break;  

            case "righto":  

                value = 2;  

                break;  

            default:  

                value = 6;  

        }  

        System.out.println(value);  

    }    

}  

 

 

字节码:

 

Java代码  


public static void main(java.lang.String[]);  

  Code:  

     0: ldc           #2                  // String buzzards  

     2: astore_1  

     3: iconst_0  

     4: istore_2  

     5: aload_1  

     6: astore_3  

     7: iconst_m1  

     8: istore        4  

    10: aload_3  

    11: invokevirtual #3                  // Method java/lang/String.hashCode:()I  

    14: lookupswitch  { // 1  

          -931102253: 32  

             default: 59  

        }  

    32: aload_3  

    33: ldc           #4                  // String righto  

    35: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)  

    38: ifeq          47  

    41: iconst_1  

    42: istore        4  

    44: goto          59  

    47: aload_3  

    48: ldc           #2                  // String buzzards  

    50: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)  

    53: ifeq          59  

    56: iconst_0  

    57: istore        4  

    59: iload         4  

    61: lookupswitch  { // 2  

                   0: 88  

                   1: 93  

             default: 98  

        }  

    88: iconst_1  

    89: istore_2  

    90: goto          101  

    93: iconst_2  

    94: istore_2  

    95: goto          101  

    98: bipush        6  

   100: istore_2  

   101: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;  

   104: iload_2  

   105: invokevirtual #7                  // Method java/io/PrintStream.println:(I)V  

   108: return  

 

 

 

这里我们看到两个字符串都跳到32行,首先跟"righto"比较,如果不相等则跳到47行比较buzzards。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java