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 ... 
随机推荐
- EMC、Pure和NetApp推新品,NAS闪存场景在哪里
			Hardy 架构师技术联盟 All Flash/SSD存储的趋势势不可挡,未来在NAS服务上也是如此,眼下已经有非常多家初创厂商支持全SSD的NAS存储服务,包含EMC Isilion也推出了全闪存节 ... 
- sqlserver、mysql怎样获取连接字符串
			sqlserver.mysql怎样获取连接字符串 步骤: 一.新建文本文档xxx.txt,改动文件类型为.udl 二.打开该文件,在<提供数据>中找到相应的服务. 三.在连接中选择须要的数 ... 
- openresty package.path require 报错
			在文件中 package.path = '/usr/local/share/lua/5.1/?.lua;/usr/local/openresty/lualib/resty/?.lua;' packag ... 
- ubuntu 按键替换 Control_R to Left
			ubuntu 按键替换 Control_R to Left 1 查看当前键盘布局 $xmodmap -pke keycode 105 = Control_R NoSymbol Control_Rkey ... 
- 第二百五十八节,Tornado框架-逻辑处理get()方法和post()方法,初识模板语言
			Tornado框架-逻辑处理get()方法和post()方法,初识模板语言 Tornado框架,逻辑处理里的get()方法,和post()方法 get()方法,处理get方式的请求post()方法,处 ... 
- 【HDU】3622 Bomb Game(2-SAT)
			http://acm.hdu.edu.cn/showproblem.php?pid=3622 又是各种逗.. 2-SAT是一种二元约束,每个点可以置于两种状态,但只能处于一种状态,然后图是否有解就是2 ... 
- 【POJ】1094 Sorting It All Out(拓扑排序)
			http://poj.org/problem?id=1094 原来拓扑序可以这样做,原来一直sb的用白书上说的dfs............ 拓扑序只要每次将入度为0的点加入栈,然后每次拓展维护入度即 ... 
- 基于struts2框架文件的上传与下载
			在开发一些社交网站时,需要有允许用户上传自己本地文件的功能,则需要文件的上传下载代码. 首先考虑的是文件的储存位置,这里不考虑存在数据库,因为通过数据库查询获取十分消耗资源与时间,故需将数据存储在服务 ... 
- ERROR getting 'android:label' attribute: attribute is not a string value
			这个的原因很多地方都有描述,原因多半是多国语言string.xml 有的有这个值, 有的没有. 关键是怎么定位? 实际上他报错的是当前处理的xml element有问题, 而出错的时候盖住了要处理的. ... 
- 编程之美 set 17 拈游戏分析 (2)
			题目 有 N 块石头河两个玩家 A 和 B. A 先将石头分成若干堆, 然后按照 BABABA... 的顺序轮流取石块, 能将剩下的石头依次取光的玩家获胜. 每次取石头时, 每个玩家只能取一堆的 m( ... 
