javap
: Java class文件分解器,其可以将不可读字节码转换为对应的可读指令。通过对照源码和指令,可以让我们了解编译器的内部工作,对于理解程序执行过程和执行效率等都有很大的帮助。本文就来介绍一下 javap 的简单使用。
认识 javap
众所周知, *.java
文件会被 java编译器转变为 *.class
字节码文件,再交由JVM转变为对应平台的机器指令,这就是 Java程序多平台兼容的关键。
1 | *.java -> *.class -> 机器指令 |
需要知道的是,编译器并不是简单的去除所不必要的东西 (如注释,换行等),再转变为 16进制文件,而是做了编译器优化,这些行为是无法直接知道的。虽然字节码也是可以被解读的,但这对人来说并不友好,而使用 JDK 提供的 javap 就可以将不可读字节码转换为对应的可读指令。
JDK 目录结构
从 JDK 目录结构可以看出 : JDK = JRE + Tools&Tool APIs 。
javap 正是 JDK 提供的开发工具之一。
1 | . |
使用 javap
这里只列举常用 javap 的常用指令。正如所见 javap -c
和 javap -v
可以满足绝大部分需求。
javap [options] class |
说明 |
---|---|
-help / —help / -? |
帮助。 |
-v / -verbose |
输出附加信息,包括绝大部分详细信息。 |
-l |
输出行号和本地变量表。 |
-package |
显示程序包/受保护的/公共类。 |
-p / -private |
显示所有类和成员。 |
-c |
对代码进行反汇编。 |
-sysinfo |
显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)。 |
-constants |
显示最终常量。 |
javap -c
这里演示一下 javap -c
的用法和功能。
*.java
1 | public class JavapTest { |
javap
是作用在 *.class
上的,先使用 javac
获得 *.java
对应的 *.class
。
如果希望直接在 shell 中使用 JDK工具,需要配置环境变量。
1 | # 在java文件目录执行,会在当前目录获得.class文件 |
1) 编译器对字符常量拼接的优化
由以下可以看出,当对字符常量的拼接时,编译器直接创建了拼接结果。
1 | 0: ldc #2 // String abc |
2) 编译器对字符引用对象拼接的优化
由以下可以看出,当对字符引用对象的拼接时,编译器会自动创建 StringBuilder
进行拼接。
1 | 3: new #3 // class java/lang/StringBuilder |
IDEA 整合 javap
使用命令编译再反编译,在日常使用时还是很麻烦的,所有这里介绍一下使用 IDEA外部工具(External Tools)
添加 javap
,这样使用起来会十分方便 。
推荐使用
javap -v
,因未知原因javap -c
并不能正常输出完整信息🤣。
添加方法
进入 preferences -> Tools -> External Tools
添加
- 设置程序位置Program :
$JDKPath$/bin/javap
。 - 设置参数Arguments :
-v $FileClass$
。 - 设置工作空间为编译输出位置Working directory :
$OutputPath$
。
使用方法
在对应文件右击 External Tools
即可使用所配置的外部工具。