反编译java-维纶反编译密码
Javac 是一个编译器。 它的作用是将符合Java语言规范的源代码转换成符合Java虚拟机规范的Java字节码。 下面详细解释java中的编译和反编译。
基本概念
我们可以通过javac命令将Java程序的源代码编译成Java字节码,也就是我们常说的class文件,也就是我们通常理解的编译。 但是,字节码不是机器语言。 为了让机器执行它,需要将字节码翻译成机器指令。 这个过程是通过解释器来实现的,称为解释执行。 注意:不要把编译和解释、执行混为一谈,后面提到的后端编译过程是JVM为了提高效率所做的优化。 在不同的虚拟机实现中,执行引擎在执行字节码时反编译java,通常有解释执行(通过解释器执行)和编译执行(通过即时编译器生成本机代码执行)两种选择,或者两者兼而有之。 那么大家可以想一想,Java是编译型语言还是解释型语言? 那为什么java不直接编译成可执行文件呢? 其实主要是为了实现跨平台。 将Java源代码编译成字节码,然后由不同平台的虚拟机解释执行,从而实现一次编译,到处运行的跨平台效果。
编译原理
Java语言的编译期分为前端编译和后端编译两个阶段
前端编译
前端编译是指将*.java文件转换为*.class文件的过程,包括词法分析、句法分析、语义分析和中间代码生成。
主要有以下步骤:
后端编译
在一些商业虚拟机中,Java程序最初是通过解释器来解释和执行的。 当虚拟机发现某个方法或代码块运行特别频繁时,就会将这些代码识别为热代码。
为了提高热点代码的执行效率,虚拟机会在运行时将这些代码编译成与本地平台相关的机器码
完成这项任务的后端编译器称为即时编译器(JIT compiler)
反编译什么是反编译
由于Java编译是指将Java源代码编译成Java字节码的过程
所以Java反编译简单的说就是将Java字节码翻译成源代码的过程
为什么要反编译
首先,源码是字符编码,字节码是二进制字节流,源码是给人看的,字节码是给虚拟机用的
因此,如果要给别人看,就需要把字节码转成源码。如果要给虚拟机执行,就需要把源码编译成字节码。 当我们有一个class文件,想看源码的时候,可以使用反编译来实现。
比如你想知道编译某个Java语法糖后反编译是什么感觉; 如果有人给你发了一个jar包,你需要看看里面某个类是怎么写的。 这种情况下,可以考虑用Java反编译。 编译
反编译工具
京东图形用户界面
GitHub:github.com/java-decompiler/jd-gui
官网:java-decompiler.github.io/
Java编译与反编译 Java编译与反编译
下载后直接将class文件或jar包拖到界面即可
鲁坦
下载地址:github.com/deathmarine/Luyten/releases
阿尔萨斯
官网:arthas.aliyun.com/doc/
可以使用jad命令将运行在JVM中的类的字节码反编译成java代码
javap
javap是jdk自带的工具,可以反编译代码,查看java编译器生成的字节码
直接通过javap -help查看其用法
用法: javap
其中, 可能的选项包括:
-help --help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示最终常量
-classpath 指定查找用户类文件的位置
-cp 指定查找用户类文件的位置
-bootclasspath 覆盖引导类文件的位置
基本用途:
javac Test.java
javap -c Test.class
j类库
jclasslib是一个可视化的字节码查看工具反编译java,可以直接安装在IDEA插件中
安装完成后,IDEA编译源码后,可以选择“View”->“Show Bytecode With Jclasslib”查看字节码
可以直观的看到class文件包含了基本信息、常量池、接口信息、字段信息、方法信息和属性信息
方法信息还包括行号表、局部变量表、异常表等。
理解字节码指令涉及到很多知识。 后面的文章会通过案例详细讲解class文件结构和字节码指令的执行过程。
推荐两本很经典的书:《深入理解Java虚拟机》、《Java虚拟机规范》
反编译示例
我们来看一个简单而常见的案例:
public class ForEachDemo {
public static void main(String[] args) {
List data = new ArrayList();
data.add("a");
data.add("b");
for (String str : data) {
System.out.println(str);
}
}
}
我们直接在IDEA中编译class文件,然后在target目录下寻找class,双击打开,得到如下反编译源码:
public class ForEachDemo {
public ForEachDemo() {
}
public static void main(String[] args) {
List data = new ArrayList();
data.add("a");
data.add("b");
Iterator var2 = data.iterator();
while(var2.hasNext()) {
String str = (String)var2.next();
System.out.println(str);
}
}
}
从上面的反编译代码可以清楚的看出,当原代码中没有写构造方法时,编译器会自动生成一个默认的构造方法; foreach循环遍历链表时,底层是迭代器实现的