注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

曹兆领的博客

有志者事竟成,破釜沉舟,百二秦关终属楚!

 
 
 

日志

 
 

java中对switch的处理  

2009-12-08 10:56:27|  分类: Java开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

转自http://blog.csdn.net/ZangXT/archive/2009/01/14/3777897.aspx
te< te<

    switch是控制选择的一种方式,编译器生成代码时可以对这种结构进行特定的优化,从而产生效率比较高的代码。在java中,编译器根据分支的情况,分 别产生tableswitch,lookupswitch两中情况,其中tableswitch适用于分支比较集中的情况,而lookupswitch适 用与分支比较稀疏的情况。不过怎么算稀疏,怎么算集中就是编译器的决策问题了,这里不做深入的分析。

    简单的找几个例子。

    例一:

   


  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.         int i = 3;  
  5.         switch (i) {  
  6.             case 0:  
  7.                 System.out.println("0");  
  8.                 break;  
  9.             case 1:  
  10.                 System.out.println("1");  
  11.                 break;  
  12.             case 3:  
  13.                 System.out.println("3");  
  14.                 break;  
  15.             case 5:  
  16.                 System.out.println("5");  
  17.                 break;  
  18.             case 10:  
  19.                 System.out.println("10");  
  20.                 break;  
  21.             case 13:  
  22.                 System.out.println("13");  
  23.                 break;  
  24.             case 14:  
  25.                 System.out.println("14");  
  26.                 break;  
  27.         default:  
  28.         System.out.println("default");  
  29.                 break;  
  30.         }  
  31.   
  32.   
  33.     }  
  34. }  
public class Test { public static void main(String[] args) { int i = 3; switch (i) { case 0: System.out.println("0"); break; case 1: System.out.println("1"); break; case 3: System.out.println("3"); break; case 5: System.out.println("5"); break; case 10: System.out.println("10"); break; case 13: System.out.println("13"); break; case 14: System.out.println("14"); break; default: System.out.println("default"); break; } } }

反汇编代码可以发现其跳转表的结构:


  1. Code:  
  2.    0:   iconst_3  
  3.    1:   istore_1  
  4.    2:   iload_1  
  5.    3:   tableswitch{ //0 to 14  
  6.         076;  
  7.         187;  
  8.         2153;  
  9.         398;  
  10.         4153;  
  11.         5109;  
  12.         6153;  
  13.         7153;  
  14.         8153;  
  15.         9153;  
  16.         10120;  
  17.         11153;  
  18.         12153;  
  19.         13131;  
  20.         14142;  
  21.         default153 }  
  22.    76:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  23.    79:  ldc #3//String 0  
  24.    81:  invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  25.    84:  goto    161  
  26.    87:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  27.    90:  ldc #5//String 1  
  28.    92:  invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  29.    95:  goto    161  
  30.    98:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  31.    101: ldc #6//String 3  
  32.    103: invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  33.    106goto    161  
  34.    109: getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  35.    112: ldc #7//String 5  
  36.    114: invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  37.    117goto    161  
  38.    120: getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  39.    123: ldc #8//String 10  
  40.    125: invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  41.    128goto    161  
  42.    131: getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  43.    134: ldc #9//String 13  
  44.    136: invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  45.    139goto    161  
  46.    142: getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  47.    145: ldc #10//String 14  
  48.    147: invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  49.    150goto    161  
  50.    153: getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  51.    156: ldc #11//String default  
  52.    158: invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  53.    161return  
Code: 0: iconst_3 1: istore_1 2: iload_1 3: tableswitch{ //0 to 14 0: 76; 1: 87; 2: 153; 3: 98; 4: 153; 5: 109; 6: 153; 7: 153; 8: 153; 9: 153; 10: 120; 11: 153; 12: 153; 13: 131; 14: 142; default: 153 } 76: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 79: ldc #3; //String 0 81: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 84: goto 161 87: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 90: ldc #5; //String 1 92: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 95: goto 161 98: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 101: ldc #6; //String 3 103: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 106: goto 161 109: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 112: ldc #7; //String 5 114: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 117: goto 161 120: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 123: ldc #8; //String 10 125: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 128: goto 161 131: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 134: ldc #9; //String 13 136: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 139: goto 161 142: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 145: ldc #10; //String 14 147: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 150: goto 161 153: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 156: ldc #11; //String default 158: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 161: return

其中的 3: tableswitch{ //0 to 14
  0: 76;
  1: 87;
  2: 153;
  3: 98;
  4: 153;
  5: 109;
  6: 153;
  7: 153;
  8: 153;
  9: 153;
  10: 120;
  11: 153;
  12: 153;
  13: 131;
  14: 142;
  default: 153 }
就 是跳转表,对于tableswitch指令,这里high为14,low为0,表中共有high-low+1个分支项,当jvm遇到 tableswitch指令时,它会检测switch(key)中的key值是否在low~high之间,如果不是,直接执行default部分,如果在 这个范围之内,它使用key-low这个项指定的地点跳转。可见,tableswitch的效率是非常高的。

例二:


  1. public class Test2 {  
  2.   
  3.     public static void main(String[] args) {  
  4.         int i = 3;  
  5.         switch (i) {  
  6.             case 3:  
  7.                 System.out.println("3");  
  8.                 break;  
  9.             case 20:  
  10.                 System.out.println("20");  
  11.                 break;  
  12.             case 50:  
  13.                 System.out.println("50");  
  14.                 break;  
  15.             case 100:  
  16.                 System.out.println("100");  
  17.                 break;  
  18.         }  
  19.   
  20.   
  21.     }  
  22. }  
public class Test2 { public static void main(String[] args) { int i = 3; switch (i) { case 3: System.out.println("3"); break; case 20: System.out.println("20"); break; case 50: System.out.println("50"); break; case 100: System.out.println("100"); break; } } }

反汇编代码:


  1. Code:  
  2.    0:   iconst_3  
  3.    1:   istore_1  
  4.    2:   iload_1  
  5.    3:   lookupswitch{ //4  
  6.         344;  
  7.         2055;  
  8.         5066;  
  9.         10077;  
  10.         default85 }  
  11.    44:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  12.    47:  ldc #3//String 3  
  13.    49:  invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  14.    52:  goto    85  
  15.    55:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  16.    58:  ldc #5//String 20  
  17.    60:  invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  18.    63:  goto    85  
  19.    66:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  20.    69:  ldc #6//String 50  
  21.    71:  invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  22.    74:  goto    85  
  23.    77:  getstatic   #2//Field java/lang/System.out:Ljava/io/PrintStream;  
  24.    80:  ldc #7//String 100  
  25.    82:  invokevirtual   #4//Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  26.    85:  return  
Code: 0: iconst_3 1: istore_1 2: iload_1 3: lookupswitch{ //4 3: 44; 20: 55; 50: 66; 100: 77; default: 85 } 44: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 47: ldc #3; //String 3 49: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 52: goto 85 55: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 58: ldc #5; //String 20 60: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 63: goto 85 66: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 69: ldc #6; //String 50 71: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 74: goto 85 77: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 80: ldc #7; //String 100 82: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 85: return

这里使用的是lookupswitch:

3: lookupswitch{ //4
  3: 44;
  20: 55;
  50: 66;
  100: 77;
  default: 85 }
这 种情况下,必须依次检测每一个项目看是否和switch(key) 中的key匹配,如果遇到匹配的直接跳转,如果遇到比key值大的,执行default,因为3,20,50,100这些项目是按照升序排列的,所以遇到 比 key值大的case值后就可以确定后面没有符合条件的值了。另外一点,升序排列也允许jvm实现这条指令时进行优化,比如采用二分搜索的方式取代线性扫 描等。

     最后,记住jvm规范中的几句话:

  Compilation of de<switchde< statements uses the tableswitch and lookupswitch instructions. The tableswitch instruction is used when the cases of the de<switchde< can be efficiently represented as indices into a table of target offsets. The de<defaultde< target of the de<switchde< is used if the value of the expression of the de<switchde< falls outside the range of valid indices.

  Where the cases of the de<switchde< are sparse, the table representation of the tableswitch instruction becomes inefficient in terms of space. The lookupswitch instruction may be used instead.

  The Java virtual machine specifies that the table of the lookupswitch instruction must be sorted by key so that implementations may use searches more efficient than a linear scan. Even so, the lookupswitch instruction must search its keys for a match rather than simply perform a bounds check and index into a table like tableswitch. Thus, a tableswitch instruction is probably more efficient than a lookupswitch where space considerations permit a choice.

  评论这张
 
阅读(366)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017