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 ...
随机推荐
- hdu6153 扩展kmp求一个字符串的后缀在另一个字符串出现的次数。
/** 题目:hdu6153 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6153 题意:给定两个串,求其中一个串t的每个后缀在另一个串s中出现的次数乘以 ...
- 解决异常:Package should contain a content type part [M1.13]
http://blog.csdn.net/llwan/article/details/8890190 ————————————————————————————————————————————————— ...
- CMake Error at cmake/boost.cmake:76 (MESSAGE):
编译mysql5.7.9的时候报错 CMake Error at cmake/boost.cmake:76 (MESSAGE): You can download it with -DDOWNLOAD ...
- js学习笔记25----Event对象
Event : 事件对象,当一个事件发生的时候,和当前这个对象发生的这个事件有关的一些详细的信息都会被临时保存到一个指定的地方-event 对象,供我们在需要时调用. 事件对象必须在一个事件调用的函数 ...
- ComBoFuzzySearch.js
/** * combobox和combotree模糊查询 */(function () { //combobox可编辑,自定义模糊查询 $.fn.combobox.defaults.editable ...
- media wiki run on nginx
1. 环境安装: nginx安装 nginx-1.5.7 php安装 PHP 5.4.10 (cli) (built: Jul 30 2014 16:45:08) mysql安装 Ver 14.14 ...
- 自己开发iOS版按键精灵--TTouch
利用闲余时间,把之前的按键录制和播放整理了一些,开发了一个iOS版按键录制.播放的越狱APP,类似按键精灵.触动精灵等按键类的基本功能.脚本采用lua语法格式,可直接执行lua脚本,通过lua和obj ...
- 隐马尔可夫树(HMT模型)
HMT(Hidden Markov Tree)隐马尔可夫树 [论文] 小波变换与HMT模型的图像插值算法-郭昌-中山大学学报(自然科学版)
- php7垃圾回收分析
- C++ string类学习总结
C++字符串技术 string类 string对象在大多数应用中被用来消除对char*指针的使用,支持所期望的一些操作; 可以转换成char*,保持和现代代码的兼容性,还能自动处理内存管理; 一些s ...