zoukankan      html  css  js  c++  java
  • [转]jdk1.7中 新增 switch 使用String 做参数 的实现

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

    看这样一个程序:

    Java代码  收藏代码
    1. public class Test {     
    2.     public static void main(String[] args) {    
    3.         String name = "b";  
    4.         int value = 0;  
    5.         switch(name) {  
    6.             case "a":  
    7.                 value = 1;  
    8.                 break;  
    9.             case "b":  
    10.                 value = 2;  
    11.                 break;  
    12.             case "c":  
    13.                 value = 3;  
    14.                 break;  
    15.             case "d":  
    16.                 value = 4;  
    17.                 break;  
    18.             case "e":  
    19.                 value = 5;  
    20.                 break;  
    21.             default:  
    22.                 value = 6;  
    23.         }  
    24.         System.out.println(value);  
    25.     }    
    26. }  

    javap -c Test得出的结果为:

    Java代码  收藏代码
    1. public static void main(java.lang.String[]);  
    2.   Code:  
    3.      0: ldc           #2                  // String b  
    4.      2: astore_1                    //将"b"赋值给name  
    5.      3: iconst_0                    //将0入栈  
    6.      4: istore_2                    //将0赋值给value  
    7.      5: aload_1                 //将name(即"b")入栈  
    8.      6: astore_3                    //将name(即"b")赋值给一个编译器生成的变量,记为tmpName(tmpName此时也是"b")  
    9.      7: iconst_m1                   //将-1入栈  
    10.      8: istore        4         //将-1赋值给一个编译器生成的变量,记为m1  
    11.     10: aload_3                 //将tmpName(即"b")入栈  
    12.     11: invokevirtual #3                  // Method java/lang/String.hashCode:()I       调用tmpName的hashCode方法("b".hashCode(),得结果98)  
    13.     14: tableswitch   { // 97 to 101        //根据hashCode的值到不同的分支  
    14.                   9748  
    15.                   9863                    //这里走到这个分支,跳转到63  
    16.                   9978  
    17.                  10093  
    18.                  101108  
    19.              default120  
    20.         }  
    21.     48: aload_3  
    22.     49: ldc           #4                  // String a  
    23.     51: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
    24.     54: ifeq          120  
    25.     57: iconst_0  
    26.     58: istore        4  
    27.     60goto          120  
    28.     63: aload_3                         //从14跳转到了这里,将tmpName(即"b")入栈  
    29.     64: ldc           #2                  // String b       将"b"入栈  
    30.     66: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z     
    31.                                     //比较tmpName和"b",如果相等,将1入栈,不等将0入栈.这里是相等的,入栈的为1  
    32.     69: ifeq          120                   //从栈顶取出比较结果,如果等于0,就跳到120,如果不等于0就继续下面的指令,这里显然不等于0  
    33.     72: iconst_1                            //将1入栈  
    34.     73: istore        4                 //将1存储到m1中  
    35.     75goto          120                   //跳到120  
    36.     78: aload_3  
    37.     79: ldc           #6                  // String c  
    38.     81: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
    39.     84: ifeq          120  
    40.     87: iconst_2  
    41.     88: istore        4  
    42.     90goto          120  
    43.     93: aload_3  
    44.     94: ldc           #7                  // String d  
    45.     96: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
    46.     99: ifeq          120  
    47.    102: iconst_3  
    48.    103: istore        4  
    49.    105goto          120  
    50.    108: aload_3  
    51.    109: ldc           #8                  // String e  
    52.    111: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
    53.    114: ifeq          120  
    54.    117: iconst_4  
    55.    118: istore        4  
    56.    120: iload         4                 //将m1(即73行存进去的1)的值入栈  
    57.    122: tableswitch   { // 0 to 4             
    58.                    0156  
    59.                    1161                   //这里走1这个分支,跳到161  
    60.                    2166  
    61.                    3171  
    62.                    4176  
    63.              default181  
    64.         }  
    65.    156: iconst_1  
    66.    157: istore_2  
    67.    158goto          184  
    68.    161: iconst_2                    //将2入栈  
    69.    162: istore_2                    //将2存储到value  
    70.    163goto          184           //跳转到184进行打印输出  
    71.    166: iconst_3  
    72.    167: istore_2  
    73.    168goto          184  
    74.    171: iconst_4  
    75.    172: istore_2  
    76.    173goto          184  
    77.    176: iconst_5  
    78.    177: istore_2  
    79.    178goto          184  
    80.    181: bipush        6  
    81.    183: istore_2  
    82.    184: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;  
    83.    187: iload_2  
    84.    188: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V  
    85.    191return  
     

    在这一堆指令中我们发现,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代码  收藏代码
    1. public class Test {     
    2.     public static void main(String[] args) {    
    3.         String name = "buzzards";  
    4.         int value = 0;  
    5.         switch(name) {  
    6.             case "buzzards":  
    7.                 value = 1;  
    8.                 break;  
    9.             case "righto":  
    10.                 value = 2;  
    11.                 break;  
    12.             default:  
    13.                 value = 6;  
    14.         }  
    15.         System.out.println(value);  
    16.     }    
    17. }  
     

    字节码:

    Java代码  收藏代码
    1. public static void main(java.lang.String[]);  
    2.   Code:  
    3.      0: ldc           #2                  // String buzzards  
    4.      2: astore_1  
    5.      3: iconst_0  
    6.      4: istore_2  
    7.      5: aload_1  
    8.      6: astore_3  
    9.      7: iconst_m1  
    10.      8: istore        4  
    11.     10: aload_3  
    12.     11: invokevirtual #3                  // Method java/lang/String.hashCode:()I  
    13.     14: lookupswitch  { // 1  
    14.           -93110225332  
    15.              default59  
    16.         }  
    17.     32: aload_3  
    18.     33: ldc           #4                  // String righto  
    19.     35: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)  
    20.     38: ifeq          47  
    21.     41: iconst_1  
    22.     42: istore        4  
    23.     44goto          59  
    24.     47: aload_3  
    25.     48: ldc           #2                  // String buzzards  
    26.     50: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)  
    27.     53: ifeq          59  
    28.     56: iconst_0  
    29.     57: istore        4  
    30.     59: iload         4  
    31.     61: lookupswitch  { // 2  
    32.                    088  
    33.                    193  
    34.              default98  
    35.         }  
    36.     88: iconst_1  
    37.     89: istore_2  
    38.     90goto          101  
    39.     93: iconst_2  
    40.     94: istore_2  
    41.     95goto          101  
    42.     98: bipush        6  
    43.    100: istore_2  
    44.    101: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;  
    45.    104: iload_2  
    46.    105: invokevirtual #7                  // Method java/io/PrintStream.println:(I)V  
    47.    108return  
     

    这里我们看到两个字符串都跳到32行,首先跟"righto"比较,如果不相等则跳到47行比较buzzards。

    原文地址:http://freish.iteye.com/blog/1152921

  • 相关阅读:
    【Elasticsearch 技术分享】—— ES 常用名词及结构
    【Elasticsearch 技术分享】—— Elasticsearch ?倒排索引?这都是什么?
    除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
    小伙伴想写个 IDEA 插件么?这些 API 了解一下!
    部署Microsoft.ReportViewe
    关于TFS强制undo他人check out
    几段查看数据库表占用硬盘空间的tsql
    How to perform validation on sumbit only
    TFS 2012 Disable Multiple Check-out
    在Chrome Console中加载jQuery
  • 原文地址:https://www.cnblogs.com/wmdzkey/p/2749273.html
Copyright © 2011-2022 走看看