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 后的结果:

 1 public class Test {
 2   public Test();
 3     Code:
 4        0: aload_0
 5        1: invokespecial #1                  // Method java/lang/Object."<init>":
 6 ()V
 7        4: return
 8
 9   public void test(java.lang.String);
10     Code:
11        0: aload_1
12        1: astore_2                ---------------从这里开始------------
13        2: iconst_m1              // 将int型-1推送至栈顶
14        3: istore_3               // 赋值,因为此时栈顶元素为-1,所以赋值-1
15        4: aload_2
16        5: invokevirtual #2                  // Method java/lang/String.hashCode: 调用hasCode方法
17 ()I
18        8: lookupswitch  { // 2        源码本来只有一次switch,现在被拆分成两次,这是第一次switch,下面还有一次公共的
19                     97: 36           case 97 : 跳至36行 aload_2
20                     98: 50           case 98 :跳至50行 aload_2
21                default: 61           default : 跳至61行 iload_3
22           }
23       36: aload_2
24       37: ldc           #3                  // String a  下面equal的内容
25       39: invokevirtual #4                  // Method java/lang/String.equals:(L  进行equal的比较
26 java/lang/Object;)Z
27       42: ifeq          61           // if 语句
28       45: iconst_0               // 将int型0推送至栈顶
29       46: istore_3               // 赋值,因为此时栈顶元素为 0 ,所以赋值0
30       47: goto          61
31       50: aload_2
32       51: ldc           #5                  // String b   下面equal的内容
33       53: invokevirtual #4                  // Method java/lang/String.equals:(L  进行equal的比较
34 java/lang/Object;)Z
35       56: ifeq          61           // if 语句
36       59: iconst_1               // 将int型1推送至栈顶 
37       60: istore_3               // 赋值,因为此时栈顶元素为 1 , 所以赋值1
38       61: iload_3                ----------------到这里结束---------------
39       62: lookupswitch  { // 2
40                      0: 88
41                      1: 99
42                default: 110
43           }
44       88: getstatic     #6                  // Field java/lang/System.out:Ljava/
45 io/PrintStream;
46       91: ldc           #3                  // String a
47       93: invokevirtual #7                  // Method java/io/PrintStream.printl
48 n:(Ljava/lang/String;)V
49       96: goto          118
50       99: getstatic     #6                  // Field java/lang/System.out:Ljava/
51 io/PrintStream;
52      102: ldc           #5                  // String b
53      104: invokevirtual #7                  // Method java/io/PrintStream.printl
54 n:(Ljava/lang/String;)V
55      107: goto          118
56      110: getstatic     #6                  // Field java/lang/System.out:Ljava/
57 io/PrintStream;
58      113: ldc           #8                  // String default
59      115: invokevirtual #7                  // Method java/io/PrintStream.printl
60 n:(Ljava/lang/String;)V
61      118: return
62 }

javac 编译 , javap -c 反编译 Test2 后的结果:

 1 public class Test2 {
 2   public Test2();
 3     Code:
 4        0: aload_0
 5        1: invokespecial #1                  // Method java/lang/Object."<init>":
 6 ()V
 7        4: return
 8
 9   public void test(int);
10     Code:
11        0: iload_1
12        1: lookupswitch  { // 2
13                      1: 28
14                      2: 39
15                default: 50
16           }
17       28: getstatic     #2                  // Field java/lang/System.out:Ljava/
18 io/PrintStream;
19       31: ldc           #3                  // String 1
20       33: invokevirtual #4                  // Method java/io/PrintStream.printl
21 n:(Ljava/lang/String;)V
22       36: goto          58
23       39: getstatic     #2                  // Field java/lang/System.out:Ljava/
24 io/PrintStream;
25       42: ldc           #5                  // String 2
26       44: invokevirtual #4                  // Method java/io/PrintStream.printl
27 n:(Ljava/lang/String;)V
28       47: goto          58
29       50: getstatic     #2                  // Field java/lang/System.out:Ljava/
30 io/PrintStream;
31       53: ldc           #6                  // String default
32       55: invokevirtual #4                  // Method java/io/PrintStream.printl
33 n:(Ljava/lang/String;)V
34       58: return
35 }

  大家看到这么多字节码是不是有点头晕不想再看下去了?其实只需稍稍观察比较就能发现”从这里开始“——”到这里结束“中间那些字节码是下面那个字节码文件所没有的,所以我们研究这几行代码就行了。又看我用红色字体标出来的注释,结果就显而易见了:

(0)用一个int类型变量代表String类型变量

(1)获取String字符串的hashCode

(2)case hashCode

(3)用if语句处理String

(4)为int类型的变量赋值

(5)真正的swtich,现在传入的是上面得出的int类型变量。

把上面的字节码文件翻译成java即:

 1 public class test {
 2
 3     public void test(String str) {
 4
 5         int i = -1;
 6
 7         switch(str.hashCode()){
 8
 9         case 97:
10             if(str.equals("a")){
11                 i = 0;
12             }
13             break;
14         case 98:
15             if(str.equals("b")){
16                 break;
17             }
18         }
19
20         switch(i) {
21
22         case 0:
23             System.out.println("a");
24             break;
25
26         case 1:
27             System.out.println("b");
28             break;
29
30         default:
31             System.out.println("default");
32         }
33     }
34 }

java7(1)——反编译深入理解增强的switch,布布扣,bubuko.com

时间: 2024-11-25 05:57:51

java7(1)——反编译深入理解增强的switch的相关文章

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

一,用jd-gui.exe等工具查看源代码.如何你不会,可以参看此文章: http://blog.csdn.net/hp_2008/article/details/8207879 可以到以下连接下载可视化反编译工具: http://download.csdn.net/detail/hp_2008/5099046 二,反编译后的源代码,是乱的,看不太懂.这是因为开发者在发布APK时,一般都会用代码混淆器将原始的源代码打乱,这也是防盗的一种方法.但是再怎样防,道高一尺,魔高一丈,用反编译工具很轻松的

通过反编译字节码来理解 Java 枚举

枚举的声明很简单, 像 enum Gender { Male, Female }, 其余事情就是 Java 编译器帮我们干的了,所以 enum 也就是一块语法糖.有了枚举确实是很方便,避免了传统常量的无范围性.那么编译器到底在后面做了什么呢?以及理解了这个之后我们可以怎么去使用 Java 的枚举, 下面就从这个例子说起: public enum Gender {    Male,    Female} 把上面的编译成 Gender.class, 然后用  javap -c Gender 反编译出

Java代码的编译与反编译那些事儿

编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language).编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language). 机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序. 而C.C++.Java.Python等属于高级语言,用语句(Statement)编写程序,语句是计算

Java 编译与反编译

编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language).编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language). 机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序. 而C.C++.Java.Python等属于高级语言,用语句(Statement)编写程序,语句是计算

反编译Android APK及防止APK程序被反编译

原文出处 反编译Android APK及防止APK程序被反编译 怎么逆向工程对Android Apk 进行反编译 google Android开发是开源的,开发过程中有些时候会遇到一些功能,自己不知道该怎么做,然而别的软件里面已经有了,这个时候可以采用反编译的方式,解开其他的程序,来了解一些它 的做法,同时啊,还可以借鉴别人的软件结构,资源文件:作为一个开发者,你可能会很想知道这些效果界面是怎么去实现的,这时,你便可以对改应用的APK进行反编译查看.此方式主要目的是为了促进开发者学习,借鉴好的代

手把手教你反编译别人的app

虽然iOS系统相比于其他手机操作系统相对安全,但是这个安全并不是绝对的,我一直相信,道高一尺魔高一丈.此文想以实际例子出发,告诉大家,如何去反编译一个app,并且从某个角度来说,iOS没有传说中的"安全". 这里只最简单的结论给大家,具体原理以及工具的详细使用,请各位自行Google,为什么这么做呢,因为我想用最简单的语言,让没有汇编基础的同学也能明白. 将用以下几个方面来阐述我的观点: iOS app可以"有条件"地被反编译 脱掉App Store给"二

介绍一点.NET反编译的知识

反编译是我们理解.NET内部实现的一种良好的手段. 程序编译时 Test.exe是IL代码.我们可以通过一些工具,来查看这些IL代码. 一模一样? 理论上来说,一模一样的反编译是不存在的.原因有以下3点: 1. 注释不通过编译程序,自然木有注释. 2. .NET编译器会做一些优化,例如 int i= 5+6 : 编译时直接表述成 i=11了.无用变量直接过滤. (i=5+6这种方式写代码不是没有必要的,有些时候,例如文件操作中定义文件大小,我们经常为了可读性,写成(7*1024*1024*...

初识Ildasm.exe——IL反编译的实用工具

原文地址:http://www.cnblogs.com/yangmingming/archive/2010/02/03/1662307.html Ildasm.exe 概要: 一.前言: 微软的IL反编译实用程序——Ildasm.exe,可以对可执行文件(ex,经典的控制台Hello World 的 exe 可执行文件)抽取出 IL 代码,并且给出命名空间以及类的视图.在讲述如何反编译之前,有必要从虚拟CPU的角度来看CLR,这样有助于先从正面了解代码执行过程. 虚拟CPU: .NET 程序,其

Android开发之反编译与防止反编译

防止反编译是每个程序员的必修课,因为当你辛辛苦的研发一个应用,被人家三下五除二给反编译了,是一件多么尴尬的事啊.那么如何防止反编译啊?这里就用Google Android自带的代码混编的方式来防止反编译.孙子兵法中讲得好:"知彼知己百战不殆",所以在讲解防止反编译之前,先让我们了解一下如何反编译一个应用. 一.反编译Android应用 实验环境: Windows8.1企业版.dex2jar-0.0.9.9 反编译工具包: Android反编译工具包(升级版) 1.将Apk反编译得到Ja