最近在补充JVM相关知识,开始学着看Java字节码反编译结果,
对于目前的我而言,只是单纯地补充知识,没有实际的应用启发,
不过,还是要丰富自己的底层知识,
现整理学习过程的测试文档,分享如下,
帮助读者可以快速掌握反编译Java类,查看相关字节码的汇编信息。
JDK8的javap官网文档地址:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javap.html
通过javap -help即可查看javap的参数,
Windows10中文平台会直接给出中文描述,
结果如下图所示。
javap -h
由图可知,JDK版本为1.8.0_291,支持invokedynamic,运行时解析调用方法。
这里先给出完整的原始类:ByteCodeTest.java,为后面生成字节码及反编译做准备,
其中,方法调用给出了5种,分别对应如下反编译标识:
package com.monkey.java_study.clzz;
import com.monkey.java_study.common.entity.UserEntity;
import com.monkey.java_study.proxy.jdk_proxy.IUserService;
import com.monkey.java_study.proxy.jdk_proxy.impl.UserServiceImpl;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 字节码反编译测试.
*
* @author xindaqi
* @since 2022-08-11 10:48
*/
public class ByteCodeTest {
public static final String TEST_NAME = "hello world!";
private void test() {
System.out.println(">>>>>>>>I am test method in current class");
}
public static void main(String[] args) {
ByteCodeTest byteCodeTest = new ByteCodeTest();
// invokespecial:调用当前类方法
byteCodeTest.test();
String var1 = "a";
String var2 = "b";
UserEntity userEntity = new UserEntity();
// invokevirtual:调用其他类的方法
userEntity.getNickname();
IUserService userService = new UserServiceImpl();
// invokeinterface
userService.add();
List<String> var4 = Stream.of("a", "b", "c").collect(Collectors.toList());
// invokedynamic:运行时解析,调用方法,
// invokeinterface:forEach为接口方法
var4.forEach(s -> {
if ("a".equals(s)) {
// invokestatic:System中out为static方法
System.out.println(">>>>>>>>I am " + s);
}
});
}
}
这里使用集成开发环境IDEA,通过build项目将ByteCodeTest.java编译为字节码,
操作方式如下图所示:
存储在target文件夹下,具体的位置:D:/java-basic-with-maven/target/classes/com/monkey/java_study/clzz/ByteCodeTest.class
编译后项目目录树如下图所示:
这里使用类文件路径方式反编译,即javap [options] class-file-path
其中,class-path-file为类文件路径。
查看附加信息。
javap -v ByteCodeTest.class
结果如下图所示,简单的讲解,最前面的信息有:类文件大小、类文件的MD5、JDK版本等,
通过-v看到的信息比较完整,但是比较多,通过-c查看相关反编译指令。
输出行号和本地变量表。
javap -l ByteCodeTest.class
首先,可以看到原始代码的行号与字节码表的标识对应关系,如下图所示,
后面查看字节码序号时可以反查是哪一行的源码。
本地变量签名结果如下图所示。
显示公共类和成员。
javap -public ByteCodeTest.class
显示受保护的/公共类和成员
javap -protected ByteCodeTest.class
显示程序包/受保护的/公共类
javap -package ByteCodeTest.class
显示所有类和成员
javap -p ByteCodeTest.class
对代码进行反汇编。
javap -c ByteCodeTest.class
输出内部类型签名。
javap -s ByteCodeTest.class
显示正在处理类的系统信息(路径、大小、日期、MD5)
javap -sysinfo ByteCodeTest.class
查看最终常量。
javap -constants ByteCodeTest.class
(1)javap命令反汇编一个或多个class文件。输出依赖使用的参数,若不使用参数,直接使用javap命令会打印protected和public限定的类属性和方法。
(2)javap命令不支持多版本jar。通过类路径形式使用javap命令只能查看当前jar文件的类文件反编译结果,通过URL形式使用javap命令只能查看指定版本类文件的反编译结果。
(3)javap命令直接将结果打印到控制台。
(4)常用查看汇编的命令:javap -c。