龙空技术网

「编译引擎」-学习阅读Class文件结构(javap版)

猴王无敌 103

前言:

如今朋友们对“javacontentpane”可能比较珍视,咱们都想要知道一些“javacontentpane”的相关内容。那么小编也在网上汇集了一些关于“javacontentpane””的相关文章,希望大家能喜欢,兄弟们一起来学习一下吧!

1.前言

在《【编译引擎】学习阅读Class文件结构(16进制版)》中,我们一起直接阅读了Class文件的16进制版本。

虽然这种方式可以帮助我们深刻理解Class文件结构,但如果您从事的是应用软件开发(而不是编译器相关工作),这样就比较低效了。

今天我们就来看看JVM提供的javap,如何提升我们解读Class结构的工作效率。

2.javap2.1.命令行学习方法

最好的学习资源就是官方文档:

在这里,我们可以获得最全面的javap使用指导。

2.2.命令行详解2.2.1.javap的命令行结构

javap [options] classfiles...

[options]:javap的命令行选项

classfiles:是我们需要反汇编的一个或多个类文件。

2.2.2.最常用的options

实战中,比较常用的options是输出所有显示所有类和成员、输出类的附件信息(如:堆栈大小、局部变量数量和方法的参数)

javap -v -p Test.class

其中,

-v:输出类的附件信息(如:堆栈大小、局部变量数量和方法的参数)-p:显示所有的类和成员2.2.3.梳理options

在官方文档中,javap的options很多,笔者做了这样的归类:

与类有关的options:

-l:打印行和局部变量表

-package:显示程序包/受保护的/公共类和成员 (默认)

-public:只显示公共类和成员

-protected:只显示受保护的和公共的类和成员

-p -private:显示所有的类和成员

-s:打印内部类型签名

-constants:显示static final常量

-c:打印类中每个方法的反汇编代码,例如,组成Java字节码的指令

-v,-verbose:打印堆栈大小、局部变量数量和方法的参数

与JVM有关的options:

-classpath <path>,-cp <path>:指定javap命令用于查找类的路径。覆盖默认的CLASSPATH环境变量 -bootclasspath <path>:指定加载引导类的路径。默认情况下,引导类是实现位于jre/lib/rt.jar和其它几个jar -extdir dirs:覆盖扩展类的位置。扩展的默认位置是java.ext.dirs的值 Joption:将指定的选项传递给JVM(JVM的options详见java命令文档) eg: javap -J-version javap -J-Djava.security.manager -J-Djava.security.policy=MyPolicy MyClassName -sysinfo:显示正在处理的类的系统信息(路径、大小、日期、MD5哈希值)

2.2.4.javap的形和神

前面解读了javap的命令行手册,这些只能算作javap的形,也比较好掌握,我们看看官方文档的javap输出的例子:

Compiled from "HelloWorldFrame.java"public class HelloWorldFrame extends javax.swing.JFrame {  java.lang.String message;   public HelloWorldFrame();    Code:       0: aload_0       1: invokespecial #1        // Method javax/swing/JFrame."<init>":()V       4: aload_0       5: ldc           #2        // String Hello World!       7: putfield      #3        // Field message:Ljava/lang/String;      10: aload_0      11: new           #4        // class HelloWorldFrame$1      14: dup      15: aload_0      16: invokespecial #5        // Method HelloWorldFrame$1."<init>":(LHelloWorldFrame;)V      19: invokevirtual #6        // Method setContentPane:(Ljava/awt/Container;)V      22: aload_0      23: bipush        100      25: bipush        100      27: invokevirtual #7        // Method setSize:(II)V      30: return   public static void main(java.lang.String[]);    Code:       0: new           #8        // class HelloWorldFrame       3: dup       4: invokespecial #9        // Method "<init>":()V       7: astore_1       8: aload_1       9: iconst_1      10: invokevirtual #10       // Method setVisible:(Z)V      13: return}

不了解JVM字节码的程序猿依然看不懂,这些就是javap的神。

这就好像辟邪剑法辟邪剑谱的关系。

接下来,我们就来解读一下javap的输出结果——字节码。

3.javap输出结果解读3.1.字节码的基础知识

为了便于不太了解JVM字节码的程序猿更快进入下一章节,我们简单回顾和小结一下字节码的知识:

STEP1.我们通过java命令,将.java文件转化为.class文件(也就是字节码)STEP2.字节码文件本身是什么呢?我们可以用16进制编辑器打开它

字节码文件本身就是一串字节流。

STEP3.为了看的更加清楚一些,我们将有关联的字节用同一种颜色着色:

如果您做过网络协议的开发,会发现字节码(字节流)与协议栈(如:ModBus)的逻辑很类似,几个字节为一组表达一个信息。

STEP4.抽象一下上述着色字节流,我们可以将Class文件结构抽象如下

字节码基础属性

常量池:占据字节码文件最大的篇幅

类的基本信息:包含类名的索引、类访问标识、父类名的索引、实现了多少接口等信息

字段列表:包含有多少字段,每个字段名的索引、访问标识等

方法列表:包含多少方法,每个方法名的索引、访问标识、方法的实现等

附加属性

3.2.通过示例代码,解读javap的输出

我们以一段示例代码,来解读javap的输出:

示例代码:javap输出

javap -v -p Demo2.classClassfile /C:/Demo2.class                                                                                              Last modified 2021-1-25; size 613 bytes                                                                              MD5 checksum f7c661d99330a1eefb32b6429e5a48b4                                                                        Compiled from "Demo2.java"                                                                                         public class com.firelord.zsample.lang.jvm.frontcompiler.Demo2  minor version: 0                                                                                                     major version: 52                                                                                                    flags: ACC_PUBLIC, ACC_SUPER                                                                                       Constant pool:                                                                                                          #1 = Methodref          #7.#21         // java/lang/Object."<init>":()V                                              #2 = Fieldref           #6.#22         // com/firelord/zsample/lang/jvm/frontcompiler/Demo2.field1:I                 #3 = Fieldref           #23.#24        // java/lang/System.out:Ljava/io/PrintStream;                                 #4 = String             #25            // hello world                                                                #5 = Methodref          #26.#27        // java/io/PrintStream.println:(Ljava/lang/String;)V                          #6 = Class              #28            // com/firelord/zsample/lang/jvm/frontcompiler/Demo2                          #7 = Class              #29            // java/lang/Object                                                           #8 = Utf8               field1                                                                                       #9 = Utf8               I                                                                                           #10 = Utf8               <init>                                                                                      #11 = Utf8               ()V                                                                                         #12 = Utf8               Code                                                                                        #13 = Utf8               LineNumberTable                                                                             #14 = Utf8               LocalVariableTable                                                                          #15 = Utf8               this                                                                                        #16 = Utf8               Lcom/firelord/zsample/lang/jvm/frontcompiler/Demo2;                                         #17 = Utf8               hello                                                                                       #18 = Utf8               i                                                                                           #19 = Utf8               SourceFile                                                                                  #20 = Utf8               Demo2.java                                                                                  #21 = NameAndType        #10:#11        // "<init>":()V                                                              #22 = NameAndType        #8:#9          // field1:I                                                                  #23 = Class              #30            // java/lang/System                                                          #24 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;                                                 #25 = Utf8               hello world                                                                                 #26 = Class              #33            // java/io/PrintStream                                                       #27 = NameAndType        #34:#35        // println:(Ljava/lang/String;)V                                             #28 = Utf8               com/firelord/zsample/lang/jvm/frontcompiler/Demo2                                           #29 = Utf8               java/lang/Object                                                                            #30 = Utf8               java/lang/System                                                                            #31 = Utf8               out                                                                                         #32 = Utf8               Ljava/io/PrintStream;                                                                       #33 = Utf8               java/io/PrintStream                                                                         #34 = Utf8               println                                                                                     #35 = Utf8               (Ljava/lang/String;)V                                                                     {                                                                                                                      private int field1;                                                                                                    descriptor: I                                                                                                        flags: ACC_PRIVATE                                                                                                                                                                                                                      public com.firelord.zsample.lang.jvm.frontcompiler.Demo2();                                                            descriptor: ()V                                                                                                      flags: ACC_PUBLIC                                                                                                    Code:                                                                                                                  stack=2, locals=1, args_size=1                                                                                          0: aload_0                                                                                                           1: invokespecial #1                  // Method java/lang/Object."<init>":()V                                         4: aload_0                                                                                                           5: iconst_1                                                                                                          6: putfield      #2                  // Field field1:I                                                               9: return                                                                                                         LineNumberTable:                                                                                                       line 3: 0                                                                                                            line 4: 4                                                                                                          LocalVariableTable:                                                                                                    Start  Length  Slot  Name   Signature                                                                                    0      10     0  this   Lcom/firelord/zsample/lang/jvm/frontcompiler/Demo2;                                public void hello();                                                                                                   descriptor: ()V                                                                                                      flags: ACC_PUBLIC                                                                                                    Code:                                                                                                                  stack=2, locals=2, args_size=1                                                                                          0: iconst_1                                                                                                          1: istore_1                                                                                                          2: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;                             5: ldc           #4                  // String hello world                                                           7: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V                    10: return                                                                                                         LineNumberTable:                                                                                                       line 7: 0                                                                                                            line 8: 2                                                                                                            line 9: 10                                                                                                         LocalVariableTable:                                                                                                    Start  Length  Slot  Name   Signature            0      11     0  this   Lcom/firelord/zsample/lang/jvm/frontcompiler/Demo2;                                          2       9     1     i   I                                                                                }SourceFile: "Demo2.java"                                                                                             
3.2.1.Class文件基础信息

Class文件的基础信息包括:

class文件的路径class文件的修改时间、class文件的大小class文件的MD5值java文件的名称jdk的大版本/小版本号3.3.2.常量池

常量池的细节知识有很多,但是有3个关键点:

访问权限、字符串等等,都是JVM所认为的"常量"常量池中存储了多种类型的常量常量之间以类似"指针"的形式来表达源代码

例如:class Demo2,那么常量池有就会有一个UTF-8类型的常量表示"Demo2",还会有一个类的符号引用指向"Demo2"这个UTF-8的常量。

3.3.3.访问标识、类索引

在常量池的基础上,JVM首先要表达源文件中的类,类的关键要素包括:

类名:javap的输出结果中有多处呈现了类名是Demo2。类的访问权限:本例中,javap的输出就是表示Demo2类是public的,并且继承于Object类3.3.4.字段表

进一步,字节码要表达:

Demo2类中有几个字段:javap的输出告诉我们,Demo2只有1个字段field1field1字段的数据类型:从输出可以看到,field1是int类型field1字段的访问权限:从输出可以看出,field1是private3.3.5.方法表

更进一步,字节码要表达:

Demo2类中有几个方法:本例中,有一个默认的构造函数,还有一个hello方法方法的原型:从输出看,hello方法的访问权限是public,返回值是void,没有输入参数方法的具体实现:从输出看,hello方法被转换为了73~88行的JVM指令序列、行号表、局部变量表。4.总结

本文解读了javap的使用以及javap的输出结果,具体如下:

理解字节码以及JVM价值javap的学习方法javap命令行常用optionjavap命令行的options解读字节码的主体结构通过一个示例代码,演练了javap输出结果中各个section的含义5.参考资料

《深入理解Java虚拟机:JVM高级特性与最佳实践》

标签: #javacontentpane