杰瑞科技汇

如何查看Java编译后的.class文件内容?

使用 javap 命令(最常用、最推荐)

javap 是 JDK 自带的一个反汇编工具,专门用来解析 .class 文件并生成可读性较好的字节码信息,它是最常用、最标准的查看方式。

如何查看Java编译后的.class文件内容?-图1
(图片来源网络,侵删)

基本用法

你需要一个 .class 文件,如果你有一个 .java 源文件,可以先编译它:

# 编译 MyDemo.java 文件,生成 MyDemo.class
javac MyDemo.java

使用 javap 命令来查看 MyDemo.class

常用选项

javap 的强大之处在于它的各种选项。

a. 查看类的公共信息(默认)

不使用任何选项,javap 会显示类的版本、字段、方法等公共信息。

如何查看Java编译后的.class文件内容?-图2
(图片来源网络,侵删)
javap MyDemo.class

示例输出:

Compiled from "MyDemo.java"
public class MyDemo {
  public MyDemo();
  public static void main(java.lang.String[]);
}

这告诉你这是一个名为 MyDemo 的公共类,有一个公共的构造函数 public MyDemo() 和一个公共的静态主方法 public static void main(String[] args)

b. 查看详细信息(-v 或 -verbose)

这是最常用的选项,它会显示非常详细的信息,包括常量池、访问标志、字段、方法、字节码指令等。

javap -v MyDemo.class

示例输出(部分):

Classfile /path/to/MyDemo.class
  Last modified ...; size 455 bytes
  MD5 checksum ...
  Compiled from "MyDemo.java"
public class MyDemo
  minor version: 0
  major version: 52  // 对应 Java 8
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;
   ... (常量池内容非常多)
{
  public MyDemo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello, World!
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
}

这个输出非常有用:

  • Constant pool: 常量池,是 .class 文件的数据仓库。
  • Code: 方法的字节码指令。0: aload_0, 1: invokespecial 等就是 JVM 可以直接执行的指令。
  • LineNumberTable: 将字节码指令与源代码行号对应起来,方便调试。
  • descriptor: 方法的描述符,([Ljava/lang/String;)V 表示接受一个字符串数组参数,返回 void。

c. 查看常量池(-c)

-c 选项会先输出类的结构,然后紧接着输出每个方法的字节码指令。

javap -c MyDemo.class

示例输出(main方法的字节码部分):

public static void main(java.lang.String[]);
  Code:
     0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #3                  // String Hello, World!
     5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     8: return

d. 查看内部结构和行号(-l)

-l 选项会显示行号表和局部变量表。

javap -l MyDemo.class

示例输出(main方法部分):

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello, World!
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;

LocalVariableTable 显示了方法中的局部变量,Slot 是变量在栈帧中的位置。

e. 查看所有成员(包括私有的)

默认情况下,javap 只显示 publicprotected 成员。-p-private 选项可以显示所有成员,包括 private 的。

javap -p MyDemo.class

f. 查看继承关系(-s)

-s 选项会输出内部类型签名。

javap -s MyDemo.class

使用图形化工具(更直观)

如果你不习惯命令行,或者想更直观地分析类的结构,可以使用图形化工具。

IntelliJ IDEA

IDEA 内置了强大的 .class 文件查看器。

  1. 在项目中找到 .class 文件(通常在 targetbuild 目录下)。
  2. 右键点击 .class 文件,选择 "Open" 或直接双击。
  3. IDEA 会在一个新标签页中打开该文件,显示其结构,包括:
    • Overview: 类的基本信息(包名、父类、实现的接口)。
    • Fields: 所有字段(成员变量)。
    • Methods: 所有方法,点击方法可以查看其字节码、常量池引用和行号表。

Eclipse

Eclipse 也有类似的功能。

  1. 切换到 "Java" 透视图。
  2. 在包资源管理器中找到 .class 文件。
  3. 右键点击,选择 "Open With" -> "Class File Editor"
  4. 打开后,你可以看到类的层次结构、字段和方法的签名,并能导航到相关代码。

jclasslib

这是一个非常流行的、专门用于查看 .class 文件结构的插件,可以安装在 IDEA 和 Eclipse 中。

  • 功能: 它提供了一个非常清晰、美观的界面来展示常量池、字段、方法、代码属性等所有 .class 文件的内容。
  • 安装: 在 IDEA/Eclipse 的插件市场中搜索 "jclasslib" 并安装。
  • 使用: 安装后,右键点击 .class 文件,选择 "Open in jclasslib Class File Viewer"。

使用专业字节码分析工具(更深入)

如果你需要进行性能分析、理解代码执行流程或进行逆向工程,可以使用更专业的工具。

Bytecode Viewer (BCV)

这是一个功能极其强大的开源字节码查看器和编辑器。

  • 特点:
    • 支持反编译为 Java、Kotlin、Scala 等多种语言。
    • 支持字节码级别的编辑和重编译。
    • 集成了多种反编译器(如 CFR, Procyon, Fernflower)。
    • 图形化界面,操作直观。
  • 适用场景: 逆向工程、代码混淆分析、恶意软件分析、深度字节码学习和修改。

CFR

CFR 是一个业界领先的反编译器,命令行工具,反编译质量非常高。

  • 特点:
    • 反编译生成的代码可读性好,能还原很多复杂的结构(如 try-catch-finallyswitch 等)。
    • 支持最新的 Java 版本。
  • 使用示例:
    # 将 MyDemo.class 反编译为 MyDemo.java 文件
    cfr MyDemo.class

    它会直接在控制台输出反编译后的 Java 代码,或者你可以使用 -o 参数指定输出文件。


总结与对比

工具/方法 优点 缺点 适用场景
javap JDK自带,无需安装;功能全面,可精确查看字节码指令。 命令行,输出格式固定,不够直观。 日常开发、调试、学习JVM指令的首选。
IDEA/Eclipse内置查看器 图形化界面,与开发环境无缝集成;方便查看行号、跳转到源码。 功能相对 javap 简单,无法像 javap -v 那样显示所有字节码细节。 快速了解类的结构、继承关系和成员
jclasslib插件 界面美观,专门为查看.class文件设计;常量池等信息展示清晰。 需要安装插件,功能专注于查看,不能编辑。 深入学习.class文件格式、常量池等。
Bytecode Viewer (BCV) 功能最强大,支持反编译、编辑、重编译;集成多种工具。 功能过于复杂,学习成本高;非轻量级工具。 逆向工程、代码混淆分析、深度字节码修改
CFR 反编译质量顶尖,生成的代码可读性极高。 本质是反编译器,不直接展示原始字节码结构。 .class文件还原成可读的Java源代码

给你的建议:

  • 如果你只是想快速看一下类的方法和结构:使用 IDEA/Eclipse 的内置查看器。
  • 如果你想学习JVM,或者调试性能问题:熟练掌握 javap -v 是必不可少的。
  • 如果你想深入理解.class文件的内部结构(如常量池):安装 jclasslib 插件。
  • 如果你想把.class文件变回.java文件:使用 CFR
分享:
扫描分享到社交APP
上一篇
下一篇