原创
  • 2020-08-02
  • 浏览 (3)
  • 评论 (0)

Java 类文件结构

Class 文件格式采用一种类似于 C 语言结构体的伪结构来存储数据,这种伪结构只有两种数据类型:无符号数和表。

无符号数属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个字节、8 个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8 编码构成字符串值。

表是由多个无符号数或者其他表数据作为数据项构成的复合数据类型,所有表习惯地以 "_info" 结尾。表用于描述有层次关系的复合结构的数据,整个 Class 文件本质上就是一张表。

Class 文件结构

image

以下面的 Java 类为例,分析它的 class 文件结构

package cn.blogss.main;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.print("Hello World.");
    }
}
16 进制表示的 HelloWorld.class

image

魔数:CA FE BA BE

次版本号 (00 00):0

主版本号 (00 34):52

常量池容量计数值 (00 1D):29-1 = 28

常量池

第 1 项常量,CONSTANT_Methodref_info

0A:tag == 10
00 06:index == 6
00 0F:index == 15

第 2 项常量,CONSTANT_Fieldref_info

09:tag == 9
00 10:index == 16
00 11:index = 17

第 3 项常量,CONSTANT_String_info

08:tag == 8
00 12:index == 18

第 4 项常量,CONSTANT_Methodref_info

0A:tag == 10
00 13:index == 19
00 14:index == 20

第 5 项常量,CONSTANT_Class_info

07:tag == 7
00 15:index == 21

第 6 项常量,CONSTANT_Class_info

07:tag == 7
00 16:index == 22

第 7 项常量,CONSTANT_Utf8_info

01:tag == 1
00 06:length == 6
3C 69 6E 69 74 3E:bytes == "<init>"

第 8 项常量,CONSTANT_Utf8_info

01:tag == 1
00 03:length == 3
28 29 56:bytes == "()V"

第 9 项常量,CONSTANT_Utf8_info

01:tag == 1
00 04:length == 4
43 6F 64 65:bytes == "Code"

第 10 项常量,CONSTANT_Utf8_info

01:tag == 1
00 0F:length == 15
4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65:bytes == "LineNumberTable"

第 11 项常量,CONSTANT_Utf8_info

01:tag == 1
00 04:length == 4
6D 61 69 6E:bytes == "Main"

第 12 项常量,CONSTANT_Utf8_info

01:tag == 1
00 16:length == 22
省略:bytes == "([Ljava/lang/String;)V"

第 13 项常量,CONSTANT_Utf8_info

01:tag == 1
00 0A:length == 10
省略:bytes == "SourceFile"

第 14 项常量,CONSTANT_Utf8_info

01:tag == 1
00 0F:length == 15
省略:bytes == "HelloWorld.java"

后面就不一一分析了。根据 class 文件我们就能推导出所有的常量。利用 javap -v HelloWorld.class 反编译得到的常量池结果和我们推导的结果是一致的,如图:

image

访问标志(u2)

00 21,0x0001 与 0x0020 的或运算的结果为 0x0021,所以这是个 public 修饰的类。

访问标志(access_flags)占两个字节,用于识别一些类或者接口的层次的访问信息,包括:这个是类还是接口;是否定义 public 类型;是否定位 abstract 类型;如果是类的话,是否被声明为 final 等。

标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为 public 类型
ACC_FINAL 0x0010 是否被声明为 final,只有类可以设置
ACC_SUPER 0x0020 JDK 1.0.2 之后编译出来的类这个标志都必须为真
ACC_INTERFACE 0x0200 标志这是一个接口
ACC_ABSTRACT 0x4000 是否为 abstract 类型,对于接口和或抽象类来说,此标志值为真,其他类值为假
ACC_SYNTHETIC 0x1000 标志这个类并非由用户代码产生
ACC_ANNOTATION 0x2000 标志这是一个注解
ACC_ENUM 0x4000 标志这是一个枚举
访问标志

类索引、父类索引与接口索引集合

  1. 类索引(u2),00 05 == 5 对应第 5 项常量 cn/blogss/main/HelloWorld
  2. 父类索引(u2),00 06 对应第 6 项常量 java/lang/Object
  3. 接口索引集合,因为接口计数器(u2)为 00 00,说明该类没有实现任何接口,接口的索引表就不再占用任何字节。

【参考文献】

  1. 周志明 .《深入理解 Java 虚拟机》
  2. 蒂姆·林霍尔姆,弗兰克·耶林,吉拉德·不拉查,亚里克斯·巴克利 . 《Java虚拟机规范 Java SE 8版 》
正文到此结束
本文目录