用法: javap <options> <classes>
其中, 可能的选项包括:
--help -help -h -? 输出此帮助消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息(路径、大小、日期、SHA-256 散列)
-constants 显示最终常量
--module <模块>, -m <模块> 指定包含要反汇编的类的模块
-J<vm-option> 指定 VM 选项
--module-path <路径> 指定查找应用程序模块的位置
--system <jdk> 指定查找系统模块的位置
--class-path <路径> 指定查找用户类文件的位置
-classpath <路径> 指定查找用户类文件的位置
-cp <路径> 指定查找用户类文件的位置
-bootclasspath <路径> 覆盖引导类文件的位置
--multi-release <version> 指定要在多发行版 JAR 文件中使用的版本
GNU 样式的选项可使用 = (而非空白) 来分隔选项名称
及其值。
如果只是单纯的用javap +class文件名的话,那只是单纯的反编译class文件而已。
我们都知道class文件的字节码文件,是难以理解的。
javap -v Main.class
很好理解。这里保存了最新更改时间和文件大小为414字节。
类声明:
public class Main
版本信息:
minor version: 0
major version: 61
这表示 Java 编译器的次要版本为 0,主要版本为 61。Java 版本号 61 对应 JDK 17。
访问标志:
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
这表示类具有 ACC_PUBLIC
和 ACC_SUPER
两个访问标志。
类层次结构:
this_class: #21
super_class: #2
this_class
表示当前类为索引为 21 的常量池项(#21 = Class #22 // Main
),而 super_class
表示其父类为索引为 2 的常量池项(#2 = Class #4 // java/lang/Object
)。
接口、字段、方法和属性统计:
interfaces: 0, fields: 0, methods: 2, attributes: 1
该类没有实现接口,没有字段,有两个方法,一个属性。
常量池:
Constant pool: ...
常量池包含了类中使用的常量信息,包括方法引用、字段引用、字符串等。
方法信息:
#25 = Utf8 main
#26 = Utf8 ([Ljava/lang/String;)V
这表示类中有一个名为 main
的方法,其描述符为 ([Ljava/lang/String;)V
,即主方法。
源文件信息:
#27 = Utf8 SourceFile
#28 = Utf8 Main.java
表示源文件名为 Main.java
。
构造函数:
aload_0
:将当前对象的引用加载到操作数栈上。invokespecial #1
:调用父类的构造函数。return
:返回。主函数:
getstatic #7
:从静态字段区获取java.lang.System.out
对象。ldc #13
:将字符串常量"Hello world!"加载到操作数栈上。invokevirtual #15
:调用java.io.PrintStream.println
方法,将字符串输出到控制台。return
:返回。