jdk1.7 String switch的实现

对于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.                   97: 48  
  15.                   98: 63                    //这里走到这个分支,跳转到63  
  16.                   99: 78  
  17.                  100: 93  
  18.                  101: 108  
  19.              default: 120  
  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.     60: goto          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.     75: goto          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.     90: goto          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.    105: goto          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.                    0: 156  
  59.                    1: 161                   //这里走1这个分支,跳到161  
  60.                    2: 166  
  61.                    3: 171  
  62.                    4: 176  
  63.              default: 181  
  64.         }  
  65.    156: iconst_1  
  66.    157: istore_2  
  67.    158: goto          184  
  68.    161: iconst_2                    //将2入栈  
  69.    162: istore_2                    //将2存储到value  
  70.    163: goto          184           //跳转到184进行打印输出  
  71.    166: iconst_3  
  72.    167: istore_2  
  73.    168: goto          184  
  74.    171: iconst_4  
  75.    172: istore_2  
  76.    173: goto          184  
  77.    176: iconst_5  
  78.    177: istore_2  
  79.    178: goto          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.    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代码  收藏代码
  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.           -931102253: 32  
  15.              default: 59  
  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.     44: goto          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.                    0: 88  
  33.                    1: 93  
  34.              default: 98  
  35.         }  
  36.     88: iconst_1  
  37.     89: istore_2  
  38.     90: goto          101  
  39.     93: iconst_2  
  40.     94: istore_2  
  41.     95: goto          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.    108: return  

 

 

 

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

转载于:https://www.cnblogs.com/zhangyfr/p/8493950.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/414640.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 多线程实现异步执行demo,线程池使用demo

方法1: 1、常见Runnable对象设置同步代码run运行体 class AutoSaleTicket implements Runnable {private int ticket 20;public void run() {while (true) {// 循环是指线程不停的去卖票// 当操作的是共享数据时,用同步代码块进行包围起来,这样在执行时,只能有一…

Mvc5 控制器,视图简单说明

本系列会比Mvc4更详细。Mvc4记录或没记录的东西这里也会提到。 控制器 自动装配: 一般自动装配对于添加的时候比较好用 视图: 控制器返回的视图,其实就是一些静态的HTML。动态性不好,从控制器传递少量数据,最简单使用…

前端学习(2734):重读vue电商网站44之使用 echarts

echarts 官方文档传送门 根据官方文档示例&#xff0c;我们先展示测试数据。 Javascript <template><div><!-- 面包屑导航区域 --><el-breadcrumb separator"/"><el-breadcrumb-item :to"{ path: /home }">首页</el-bre…

No fallback instance of type class found for feign client user-service(转)

No fallback instance of type class found for feign client user-service&#xff08;转&#xff09; 1、错误日志 在 feign 开启熔断&#xff0c;配置 fallback 类&#xff0c;实现当前接口的实现类时&#xff0c;报错信息如下&#xff1a; Error starting ApplicationCont…

Redis在windows下安装过程

https://www.cnblogs.com/M-LittleBird/p/5902850.html 一、下载windows版本的Redis 去官网找了很久&#xff0c;发现原来在官网上可以下载的windows版本的&#xff0c;现在官网以及没有下载地址&#xff0c;只能在github上下载&#xff0c;官网只提供linux版本的下载 官网下载…

前端学习(2735):重读vue电商网站45之项目优化上线

优化Vue项目&#xff0c;部署Vue项目 项目优化 添加进度条 nprogress 进度条官方文档传送门 打开 vue-ui 面板&#xff0c;选择依赖&#xff0c;输入 nprogress 进行安装相关依赖。 npm Javascript npm install --save nprogress在 main.js 入口文件中&#xff0c;进行相关…

Push rejected: Push to origin/master was rejected

Push rejected: Push to origin/master was rejected 1、错误日志 23:04 Maven projects need to be imported: Import Changes Enable Auto-Import23:05 4 files committed: 初始化项目23:06 Push rejected: Push to origin/master was rejected23:07 2 files …

前端学习(2736):重读vue电商网站46之执行build 时报错

Error: No module factory available for dependency type: CssDependency 解决办法&#xff1a; 参考&#xff1a;解决webpack打包报错 No module factory available for dependency type: CssDependency 在执行 build 命令期间移除所有的 console babel-plugin-transform…

@RequestParam @PathVariable

RequestParam PathVariable 1、Request参数 在访问各种各样网站时&#xff0c;经常会发现网站的URL的最后一部分形如&#xff1a;&#xff1f;xxxxyyyy&zzzzwwww。这就是HTTP协议中的Request参数&#xff0c;它有什么用呢&#xff1f;先来看一个例子&#xff1a; 在知乎中…

蓄水池抽样算法 Reservoir Sampling

2018-03-05 14:06:40 问题描述&#xff1a;给出一个数据流&#xff0c;这个数据流的长度很大或者未知。并且对该数据流中数据只能访问一次。请写出一个随机选择算法&#xff0c;使得数据流中所有数据被选中的概率相等。 问题求解&#xff1a;如果是长度已知或者有限的问题&…

Android okhttp3使用实例,OKhttp设置请求超时时间,okgo使用demo,SSL证书验证

SSL证书验证 rootca证书资源 调用 //信任所有证书 HTTPSCerUtils.setTrustAllCertificate(okHttpBuilder); //信任raw资源目录下的证书 HTTPSCerUtils.setCertificate(context, okHttpBuilder, R.raw.rootca); //传入证书…

@ResponseBody ResponseEntity

ResponseBody ResponseEntity 1、产生疑问 我们知道&#xff0c;如果在 Controller 的某个方法上加上 ResponseBody 注解&#xff0c;那么你就能拿到 json 数据。 如果你只是知道这么用&#xff0c;那么你应该知道 ResponseBody 的具体作用&#xff1a; 其将方法的返回值通过…

22图的遍历

图的遍历 图的遍历&#xff1a;搜索属于图的基本运算。树的先序遍历和按层遍历的推广。图的遍历也称搜索&#xff0c;主要有&#xff1a; 先深搜索&#xff08;depth-first search&#xff09;——深度优先搜索——dfs搜索 先广搜索&#xff08;breadth-first search&#xff0…

Cannot resolve symbol 'R',Failed to resolve: constraint-layout

1、当在github上下载demo项目在Android studio启动时&#xff0c;提示Cannot resolve symbol R。虽然提示错误&#xff0c;但是运行项目并没有问题 原因是gradle版本高于本地Android studio的gradle版本 把 classpath com.android.tools.build:gradle:3.3.1 改为 classpat…

Android Log工具类,Toast工具类,获取当前方法名称

Log新晋工具方法 public class LgqLog {private static boolean ifShowtrue;private static int sCurrentLogLevel Log.DEBUG;private static String sPrefix null;IntDef({ Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN, Log.ERROR })Retention(RetentionPolicy.SOURCE)publ…

前端学习(2739):重读vue电商网站49之第三方库使用CDN

通过 externals 加载外部 CDN 资源 默认情况下&#xff0c;通过 import 语法导入的第三方依赖包&#xff0c;最终会被打包合并到同一个文件中&#xff0c;从而导致打包成功后&#xff0c;单文件体积过大的问题。 例如上述 chunk-vendors.js 体积很大&#xff0c;原因是全部 im…

Mysql--重点1

知识预览 sql语句规范数据类型数据库操作数据表操作表记录操作查询表记录(select)多表查询完整性约束回到顶部sql语句规范 sql是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而建立的操作命令集&#xff0c;是一种功能齐全的数据库语言。 在使用它时&…

6、jeecg 笔记之 自定义excel 模板导出(一)

6、jeecg 笔记之 自定义excel 模板导出&#xff08;一&#xff09; 1、前言 jeecg 中已经自带 excel 的导出导出功能&#xff0c;其所使用的是 easypoi&#xff0c;尽管所导出的 excel 能满足大部分需求&#xff0c; 但总是有需要用到自定义 excel 导出模板&#xff0c;下文所…

Android Lambda 表达式使用实例,-

1、Lambda表达式理解 Lambda 表达式&#xff0c;也可称为闭包&#xff0c;它是推动 Java 8 发布的最重要新特性。 Lambda 允许把函数作为一个方法的参数&#xff08;函数作为参数传递进方法中&#xff09;。 使用Lambda 表达式可以使代码变的更加简洁紧凑。 2、Lambda表达式…

前端学习(2740):重读vue电商网站50之Element-UI 组件按需加载

通过 CDN 优化 ElementUI 的打包 虽然在开发阶段&#xff0c;我们启用了 element-ui 组件的按需加载&#xff0c;尽可能的减少了打包的体积&#xff0c;但是那些被按需加载的组件&#xff0c;还是占用了较大的文件体积。此时&#xff0c;我们可以将 element-ui 中的组件&#…