【本文介绍】

  本文主要讲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(读字节命令实战)的更多相关文章

  1. 通过反编译深入理解Java String及intern(转)

    通过反编译深入理解Java String及intern 原文传送门:http://www.cnblogs.com/paddix/p/5326863.html 一.字符串问题 字符串在我们平时的编码工作 ...

  2. 通过反编译深入理解Java String及intern

    一.字符串问题 字符串在我们平时的编码工作中其实用的非常多,并且用起来也比较简单,所以很少有人对其做特别深入的研究.倒是面试或者笔试的时候,往往会涉及比较深入和难度大一点的问题.我在招聘的时候也偶尔会 ...

  3. (转)通过反编译深入理解Java String及intern

    原文链接:https://www.cnblogs.com/paddix/p/5326863.html 一.字符串问题 字符串在我们平时的编码工作中用的非常多,并且用起来非常简单,所以很少有人对其做特别 ...

  4. 从反编译深入理解JAVA内部类类结构以及finalkeyword

    1.为什么成员内部类能够无条件訪问外部类的成员? 在此之前,我们已经讨论过了成员内部类能够无条件訪问外部类的成员,那详细到底是怎样实现的呢?以下通过反编译字节码文件看看到底.其实,编译器在进行编译的时 ...

  5. android apk 防止反编译技术第二篇-运行时修改字节码

    上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372.接下来我们将介绍另一种防止a ...

  6. Java| 编译和反编译

    原文链接: http://www.yveshe.com/articles/2018/05/01/1525172129089.html 什么是编程语言? 在介绍编译和反编译之前,我们先来简单介绍下编程语 ...

  7. Java 编译与反编译

    编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language).编程语言(Programming Language)分为低级语言(Low-level Lang ...

  8. JD-GUI反编译后代码逻辑分析

    一,用jd-gui.exe等工具查看源代码.如何你不会,可以参看此文章: http://blog.csdn.net/hp_2008/article/details/8207879 可以到以下连接下载可 ...

  9. apk 反编译工具的使用

    在学习android 开发的时候,我们经常回尝试使用到别人的apk,希望能了解别人怎么编写的代码,于是想要一个能实现其反编译的软件,将软件反编译出来,查看其代码. 工具/原料 反编译软件dex2jar ...

随机推荐

  1. [接口]mmc/eMMC/SD-card

    转自:http://blog.csdn.net/yazhouren/article/details/46643321 MMC(multiMedia card)是一种通信协议,支持两种模式SPI和MMC ...

  2. Qt下QTableWidget的使用

    1.QTableWidget的基本设置 ui->tableWidget->setColumnCount(11); ui->tableWidget->setRowCount(Nu ...

  3. JavaScrip——简单练习(输出方式,简单表单验证)

    <script> //输出方式 document.write(Date());//获取当前时间 document.write(1); document.write("<p& ...

  4. zend stdio 快捷键

    1.快速跳转到当前所指的函数.变量.方法.类的定义处 F3或者 ctrl+鼠标左键2.ctrl+m 编辑窗口最大化3.ctrl+d 删除当前行4.ctrl+q 定位到最后编辑的地方(全局的)5.ctr ...

  5. 嵌入式开发之davinci--- 8148/8168/8127 中的图像处理算法优化库vlib

    The Texas Instruments VLIB is an optimizedImage/Video Processing Functions Library for C programmers ...

  6. php -- 魔术方法 之 序列化和反序列化的触发函数:__sleep(),__wakeup()

    __sleep():当对象被当做文件保存时会自动触发的方法. 该方法要做的事情,就是返回一个要保存的对象数据的数组 DB.class.php中修改 再次保存效果 读取db对象 因为没有连接数据,不能操 ...

  7. 【BZOJ】1662: [Usaco2006 Nov]Round Numbers 圆环数(数位dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1662 这道题折腾了我两天啊-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 果然 ...

  8. 转:Socket服务器整体架构概述

    Socket服务器主要用于提供高效.稳定的数据处理.消息转发等服务,它直接决定了前台应用程序的性能.我们先从整体上认识一下Socket服务器,Socket服务器从架构上一般分为:网络层.业务逻辑层.会 ...

  9. 查看linux系统外网ip命令

    终端中输入 curl ipinfo.io 或者 curl ifconfig.me 即可通过IP地址检测网站提供的api获得取本机的外网IP,或者以 JSON 格式返回全部结果.

  10. iOS 7 SDK: 如何使用后台获取(Background Fetch)

    本文转载至 http://www.cocoachina.com/applenews/devnews/2013/1114/7350.html 本文主要教你如何使用iOS 7 SDK多任务处理API--B ...