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_PUBLIC0x0001是否为 public 类型
ACC_FINAL0x0010是否被声明为 final,只有类可以设置
ACC_SUPER0x0020JDK 1.0.2 之后编译出来的类这个标志都必须为真
ACC_INTERFACE0x0200标志这是一个接口
ACC_ABSTRACT0x4000是否为 abstract 类型,对于接口和或抽象类来说,此标志值为真,其他类值为假
ACC_SYNTHETIC0x1000标志这个类并非由用户代码产生
ACC_ANNOTATION0x2000标志这是一个注解
ACC_ENUM0x4000标志这是一个枚举
访问标志

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

  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版 》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值