【Java】javap(Java Class文件分解工具)

Posted by 西维蜀黍 on 2017-06-08, Last Modified on 2021-09-21

javap是JDK自带的反汇编器,可以用于查看Java编译器对Java源代码编译后,生成的字节码(ByteCode)中的详细信息。

换句话来说,javap相当于一个分解工具。使用它可以让我们更清晰的看到字节码内部包含什么东西。

同样,通过对照源代码和字节码,我们也可以了解更多关于编译器内部的工作机制。

一.参数含义

下文会用例子以对这些参数的含义进行详细介绍:

1.用法

javap <options> <classes>...

2.options可以包含的参数

(1) -help --help -?

官方解释:Print this usage message 意义:帮助

(2)-version

官方解释:Version information 意义:显示当前.class基于哪个JDK版本编译

(3) -v -verbose

官方解释:Print additional information 意义:输出额外信息(堆栈大小、各方法的locals及args参数,以及class文件的编译版本)

(4) -l

官方解释:Print line number and local variable tables 意义:输出行、局部变量表

(5)-public

官方解释:Show only public classes and members 意义:只显示public类及成员

(6)-protected

官方解释:Show protected/public classes and members 意义:只显示protected和public类及成员

(7)-package

官方解释:Show package/protected/public classes and members (default) 意义:只显示包、protected和public类及成员(这是缺省设置)

(8)-p -private

官方解释:Show all classes and members 意义:显示所有的类和成员

(9)-c

官方解释:Disassemble the code 意义:反汇编方法内部实现对应的字节码

(10)-s

官方解释:Print internal type signatures

(11)-sysinfo

官方解释:Show system info (path, size, date, MD5 hash) of class being processed

(12)-constants

官方解释:Show final constants 意义:显示所有final修饰的常量

(13) -classpath <path>

官方解释:Specify where to find user class files

(14)-cp <path>

官方解释:Specify where to find user class files

(15)-bootclasspath <path>

官方解释:Override location of bootstrap class files

二.源代码:

后文的参数解读,均基于此源代码(HelloWorld.java)编译出的字节码(HelloWorld.class)进行分析。

public class HelloWorld {
        private static final int P_1 = 1;
        public static final int P_2 = 2;
        public String publicString;
        private String privateString;
         public static void main(String[] args){
                System.out.println("Hello World!");
         }
         
         protected void protectedMethod(){
                System.out.println("protectedMethod!");
         }
         
         private void privateMethod(){
                System.out.println("privateMethod!");
         }
}

二.参数解读

1.默认参数(-package):

javap HelloWorld.class

// 等效于以下(即 只显示包、protected和public类及成员)
javap -package HelloWorld.class

注意:
  • 只有方法声明,没有方法具体实现对应的字节码汇编代码
  • private方法和字段不会被显示

2.方法和字段的显示控制参数

以下四个参数均是控制要显示的方法和字段的范围:

// 只显示public类及成员
-public                  Show only public classes and members
// 只显示protected和public类及成员
-protected               Show protected/public classes and members
// 只显示包、protected和public类及成员(这是缺省设置)
-package                 Show package/protected/public classes
                         and members (default)
// 显示所有的类和成员
-p  -private             Show all classes and members

(1)-public

javap -public HelloWorld.class

注意:
  • 只有方法声明,没有方法具体实现对应的字节码汇编代码
  • 只有 public 方法和字段会被显示

(2)-private

javap -private HelloWorld.class

注意:
  • 只有方法声明,没有方法具体实现对应的字节码汇编代码
  • public、protected、private 方法和字段都会被显示

3.-c显示方法内部实现对应的字节码汇编代码

-c用于显示方法内部实现对应的字节码汇编代码

javap -c HelloWorld.class

4.-l显示字节码代码与源代码的行号映射关系

javap -l HelloWorld.class

在源代码编译成字节码的过程中,编译器会生成一个源代码与源代码编译后的字节码的行号映射表。

这样,当在动态断点调试代码时,IDE就可以将当前运行到的二进制代码与对应源代码关联起来,最终在IDE上显示。

类似的行号映射表:
  • Objective-C 如果你做过iOS开发,并学习过Objective-C,那么你将很容易理解,-l显示的信息与.dSYM文件中存储的信息的作用是类似的。

  • TypeScript、Dart、CoffeeScript等 如果你使用过TypeScript、Dart、CoffeeScript等最终编译成JavaScript的语言,在编译时,可选择生成一个.map文件,这个.map文件中存储的信息与-l显示的信息作用是也是类似的。

5.-constants显示被修饰为final的静态常量

javap -constants HelloWorld.class

6.-v -verbose 输出额外信息(堆栈大小、各方法的locals及args参数,以及class文件的编译版本)

javap -v HelloWorld.class

7.sysinfo显示当前.class的系统信息 (路径, 大小, 日期, MD5 )

javap -sysinfo HelloWorld.class

8.-s输出内部类型签名

javap -s HelloWorld.class

参考