在介绍编译和反编译以前,咱们先来简单介绍下编程语言(Programming Language)。编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language)。java
机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序。程序员
而C、C++、Java、Python等属于高级语言,用语句(Statement)编写程序,语句是计算机指令的抽象表示。编程
举个例子,一样一个语句用C语言、汇编语言和机器语言分别表示以下:安全
计算机只能对数字作运算,符号、声音、图像在计算机内部都要用数字表示,指令也不例外,上表中的机器语言彻底由十六进制数字组成。最先的程序员都是直接用机器语言编程,可是很麻烦,须要查大量的表格来肯定每一个数字表示什么意思,编写出来的程序很不直观,并且容易出错,因而有了汇编语言,把机器语言中一组一组的数字用助记符(Mnemonic)表示,直接用这些助记符写出汇编程序,而后让汇编器(Assembler)去查表把助记符替换成数字,也就把汇编语言翻译成了机器语言。网络
可是,汇编语言用起来一样比较复杂,后面,就衍生出了Java、C、C++等高级语言。多线程
上面提到语言有两种,一种低级语言,一种高级语言。能够这样简单的理解:低级语言是计算机认识的语言、高级语言是程序员认识的语言。编程语言
那么如何从高级语言转换成低级语言呢?这个过程其实就是编译。工具
从上面的例子还能够看出,C语言的语句和低级语言的指令之间不是简单的一一对应关系,一条a=b+1
;语句要翻译成三条汇编或机器指令,这个过程称为编译(Compile),由编译器(Compiler)来完成,显然编译器的功能比汇编器要复杂得多。用C语言编写的程序必须通过编译转成机器指令才能被计算机执行,编译须要花一些时间,这是用高级语言编程的一个缺点,然而更多的是优势。首先,用C语言编程更容易,写出来的代码更紧凑,可读性更强,出了错也更容易改正。加密
将便于人编写、阅读、维护的高级计算机语言所写做的源代码程序,翻译为计算机能解读、运行的低阶机器语言的程序的过程就是编译。负责这一过程的处理的工具叫作编译器spa
如今咱们知道了什么是编译,也知道了什么是编译器。不一样的语言都有本身的编译器,Java语言中负责编译的编译器是一个命令:javac
javac是收录于JDK中的Java语言编译器。该工具能够将后缀名为.java的源文件编译为后缀名为.class的能够运行于Java虚拟机的字节码。
当咱们写完一个HelloWorld.java
文件后,咱们可使用javac HelloWorld.java
命令来生成HelloWorld.class
文件,这个class
类型的文件是JVM能够识别的文件。一般咱们认为这个过程叫作Java语言的编译。其实,class
文件仍然不是机器可以识别的语言,由于机器只能识别机器语言,还须要JVM再将这种class
文件类型字节码转换成机器能够识别的机器语言。
反编译的过程与编译恰好相反,就是将已编译好的编程语言还原到未编译的状态,也就是找出程序语言的源代码。就是将机器看得懂的语言转换成程序员能够看得懂的语言。Java语言中的反编译通常指将class
文件转换成java
文件。
有了反编译工具,咱们能够作不少事情,最主要的功能就是有了反编译工具,咱们就能读得懂Java编译器生成的字节码。若是你想问读懂字节码有啥用,那么我能够很负责任的告诉你,好处大大的。好比个人博文几篇典型的原理性文章,都是经过反编译工具获得反编译后的代码分析获得的。如深刻理解多线程(一)——Synchronized的实现原理、深度分析Java的枚举类型—-枚举的线程安全性及序列化问题、Java中的Switch对整型、字符型、字符串型的具体实现细节、Java的类型擦除等。我最近在GitChat写了一篇关于Java语法糖的文章,其中大部份内容都用到反编译工具来洞悉语法糖背后的原理。
本文主要介绍3个Java的反编译工具:javap、jad和cfr
javap
是jdk自带的一个工具,能够对代码反编译,也能够查看java编译器生成的字节码。javap
和其余两个反编译工具最大的区别是他生成的文件并非java
文件,也不像其余两个工具生成代码那样更容易理解。拿一段简单的代码举例,如咱们想分析Java 7中的switch
是如何支持String
的,咱们先有如下能够编译经过的源代码:
public class switchDemoString { public static void main(String[] args) { String str = "world"; switch (str) { case "hello": System.out.println("hello"); break; case "world": System.out.println("world"); break; default: break; } } }
执行如下两个命令:
javac switchDemoString.java javap -c switchDemoString.class
生成代码以下:
public class com.hollis.suguar.switchDemoString { public com.hollis.suguar.switchDemoString(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String world 2: astore_1 3: aload_1 4: astore_2 5: iconst_m1 6: istore_3 7: aload_2 8: invokevirtual #3 // Method java/lang/String.hashCode:()I 11: lookupswitch { // 2 99162322: 36 113318802: 50 default: 61 } 36: aload_2 37: ldc #4 // String hello 39: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 42: ifeq 61