java7(1)——反编译深入理解增强的switch(读字节命令实战)
【本文介绍】
本文主要讲java_7 的改进switch的底层实现。反编译一个使用带String的switch的demo并一步步解析反编译出来的字节命令,从编译的角度解读switch的底层实现。
【正文】
在java7中,switch()可以放进去String 类型了,这无非是一大便利。底层JVM的swtich并没有真正的改进,只是在编译阶段,编译器把关于String的switch拆分成if语句而已。
我们写一个简单的例子测试一下:
(1)Test类:switch()使用String
public class Test {
public void test(String str) {
switch(str){
case "a": System.out.println("a");break;
case "b": System.out.println("b");break;
default : System.out.println("default");
}
}
}
(2)Test2类:switch()使用int
public class Test2 {
public void test(int str) {
switch(str){
case 1: System.out.println("1");break;
case 2: System.out.println("2");break;
default : System.out.println("default");
}
}
}
javac 编译 , javap -c 反编译 Test 后的结果:
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public void test(java.lang.String);
Code:
0: aload_1
1: astore_2 ---------------从这里开始------------
2: iconst_m1 // 将int型-1推送至栈顶
3: istore_3 // 赋值,因为此时栈顶元素为-1,所以赋值-1
4: aload_2
5: invokevirtual #2 // Method java/lang/String.hashCode: 调用hasCode方法
()I
8: lookupswitch { // 2 源码本来只有一次switch,现在被拆分成两次,这是第一次switch,下面还有一次公共的
97: 36 case 97 : 跳至36行 aload_2
98: 50 case 98 :跳至50行 aload_2
default: 61 default : 跳至61行 iload_3
}
36: aload_2
37: ldc #3 // String a 下面equal的内容
39: invokevirtual #4 // Method java/lang/String.equals:(L 进行equal的比较
java/lang/Object;)Z
42: ifeq 61 // if 语句
45: iconst_0 // 将int型0推送至栈顶
46: istore_3 // 赋值,因为此时栈顶元素为 0 ,所以赋值0
47: goto 61
50: aload_2
51: ldc #5 // String b 下面equal的内容
53: invokevirtual #4 // Method java/lang/String.equals:(L 进行equal的比较
java/lang/Object;)Z
56: ifeq 61 // if 语句
59: iconst_1 // 将int型1推送至栈顶
60: istore_3 // 赋值,因为此时栈顶元素为 1 , 所以赋值1
61: iload_3 ----------------到这里结束---------------
62: lookupswitch { //
0: 88
1: 99
default: 110
}
88: getstatic #6 // Field java/lang/System.out:Ljava/
io/PrintStream;
91: ldc #3 // String a
93: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
96: goto 118
99: getstatic #6 // Field java/lang/System.out:Ljava/
io/PrintStream;
102: ldc #5 // String b
104: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
107: goto 118
110: getstatic #6 // Field java/lang/System.out:Ljava/
io/PrintStream;
113: ldc #8 // String default
115: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
118: return
}
javac 编译 , javap -c 反编译 Test2 后的结果:
public class Test2 {
public Test2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
public void test(int);
Code:
0: iload_1
1: lookupswitch { //
1: 28
2: 39
default: 50
}
28: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
31: ldc #3 // String 1
33: invokevirtual #4 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
36: goto 58
39: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
42: ldc #5 // String 2
44: invokevirtual #4 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
47: goto 58
50: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
53: ldc #6 // String default
55: invokevirtual #4 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
58: return
}
大家看到这么多字节码是不是有点头晕不想再看下去了?其实只需稍稍观察比较就能发现”从这里开始“——”到这里结束“中间那些字节码是下面那个字节码文件所没有的,所以我们研究这几行代码就行了。又看我用红色字体标出来的注释,结果就显而易见了:
(0)用一个int类型变量代表String类型变量
(1)获取String字符串的hashCode
(2)case hashCode
(3)用if语句处理String
(4)为int类型的变量赋值
(5)真正的swtich,现在传入的是上面得出的int类型变量。
把上面的字节码文件翻译成java即:
public class test {
public void test(String str) {
int i = -1;
switch(str.hashCode()){
case 97:
if(str.equals("a")){
i = 0;
}
break;
case 98:
if(str.equals("b")){
break;
}
}
switch(i) {
case 0:
System.out.println("a");
break;
case 1:
System.out.println("b");
break;
default:
System.out.println("default");
}
}
}
java7(1)——反编译深入理解增强的switch(读字节命令实战)的更多相关文章
- 通过反编译深入理解Java String及intern(转)
通过反编译深入理解Java String及intern 原文传送门:http://www.cnblogs.com/paddix/p/5326863.html 一.字符串问题 字符串在我们平时的编码工作 ...
- 通过反编译深入理解Java String及intern
一.字符串问题 字符串在我们平时的编码工作中其实用的非常多,并且用起来也比较简单,所以很少有人对其做特别深入的研究.倒是面试或者笔试的时候,往往会涉及比较深入和难度大一点的问题.我在招聘的时候也偶尔会 ...
- (转)通过反编译深入理解Java String及intern
原文链接:https://www.cnblogs.com/paddix/p/5326863.html 一.字符串问题 字符串在我们平时的编码工作中用的非常多,并且用起来非常简单,所以很少有人对其做特别 ...
- 从反编译深入理解JAVA内部类类结构以及finalkeyword
1.为什么成员内部类能够无条件訪问外部类的成员? 在此之前,我们已经讨论过了成员内部类能够无条件訪问外部类的成员,那详细到底是怎样实现的呢?以下通过反编译字节码文件看看到底.其实,编译器在进行编译的时 ...
- android apk 防止反编译技术第二篇-运行时修改字节码
上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372.接下来我们将介绍另一种防止a ...
- Java| 编译和反编译
原文链接: http://www.yveshe.com/articles/2018/05/01/1525172129089.html 什么是编程语言? 在介绍编译和反编译之前,我们先来简单介绍下编程语 ...
- Java 编译与反编译
编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language).编程语言(Programming Language)分为低级语言(Low-level Lang ...
- JD-GUI反编译后代码逻辑分析
一,用jd-gui.exe等工具查看源代码.如何你不会,可以参看此文章: http://blog.csdn.net/hp_2008/article/details/8207879 可以到以下连接下载可 ...
- apk 反编译工具的使用
在学习android 开发的时候,我们经常回尝试使用到别人的apk,希望能了解别人怎么编写的代码,于是想要一个能实现其反编译的软件,将软件反编译出来,查看其代码. 工具/原料 反编译软件dex2jar ...
随机推荐
- Groovy学习专栏
今天新开了一个groovy的学习专栏,因为最近工作中会用到Groovy模板. 然后就是在网上找了一下Groovy模板相关的东西发现ibm中在2005年就有讲到这个的,我勒个去,这么早,我初中都还没毕业 ...
- C++成员函数的存储方式
用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间. 按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码 ...
- PHP——投票
要求: 选择第一个页面的复选框值,点击提交则提交数据,点击查看结果在同一页面覆盖显示结果的投票人数,百分比和进度条,点击返回,返回第一页面 数据库为 投票 表格为diaoyanxx 表格内容为: zh ...
- socket相关函数中断后重试
慢系统调用accept,read,write被信号中断时应该重试.对于accept,如果errno为ECONNABORTED,也应该重试. connect虽然也会阻塞,但被信号中断时不能立即重试,该s ...
- Spider Studio 社区信息
Spider Studio (采集工作站) 产品页面: http://www.gdtsearch.com/products.spiderstudio.htm QQ群: 45995410 - 有人驻场解 ...
- Ajax的两个用法
1.实现的效果是:通过一个函数,里面调用Ajax,函数的返回值是Ajax成功调用之后得到的返回值. 用jQuery进行简单的演示: function getRobotInfo(id) { var ip ...
- 超酷的JavaScript叙事性时间轴(Timeline)类库
在线演示 Timeline 是我见过的最酷的展示事件随时间发展的javascript实现.你可以基于时间使用讲故事的方式来创建时间轴特效,整个时间轴以幻灯的方式来展示,你可以穿插图片,视频或者是网站, ...
- 009Maven_建立私服——报错问题
前一篇文章的建立私服一直出问题,这里的问题是: jdk6.0只支持nuxus2.5及以下的版本,要支持nexus2.6以上,必须要jdk7.0以上.不然报错,把nexus-2.6.2war包放在Tom ...
- Android 开发之环境搭建-0
Android 开发环境安装与配置 一.开发工具介绍 要进行Android应用程序开发,最起码要有两个工具,一个是Android SDK,它不仅为开发人员提供了丰富的编程接口,而且提供了相关的调试工具 ...
- php -- ziparchive::open创建zip压缩文件
语法: mixed ZipArchive::open ( string $filename [, int $flags ] ) 参数: filename:创建的zip的文件名 flags: ZIPAR ...