Java虚拟机(JVM)之字节码文件结构

我们早先提到Java虚拟机使用字节码来实现跨平台的设想。无论是什么系统,我们都可以使用Java虚拟机来解释和执行字节码文件。但实际上,字节码有一套规范,字节码的格式是“Java虚拟机规范”。Java虚拟机规范规定了Java虚拟机结构、类类文件结构、字节码指令等。类文件结构是需要理解的内容之一。

字节码文件结构是一组基于8位字节的二进制流。数据项按严格的顺序排列在Class文件中,并且紧凑,不添加任何分隔符。在字节码结构中,有两种基本数据类型来表示字节码文件格式:无符号号和表。

无符号数字属于最基本的数据类型。它使用u1、u2、U4和U8 677分别表示1字节、2字节、4字节和8字节的无符号数。无符号数字可以用来描述用UTF-8编码的数字、索引引用、数值或字符串值。例如,在下面的表中,第一行中的U4表示Class文件的前四个字节的魔术数,第二行中的U2表示JDK的次要版本号。

表是由多个无符号数字或作为数据项的其他表组成的复合数据类型。所有表通常以_info结尾。表用于描述具有分层复合结构的数据。例如,下表的第5行表示cp_info(常量池)类型的表,其中存储了该类的所有常量。

整个字节码文件本质上是一个表,它由以下部分组成:

为了便于理解,我将一个完整的表划分为以下七个部分,它们构成了一个完整的类字节码文件:

  • 魔数与Class文件版本
  • 常量池
  • 访问标志
  • 类索引、父类索引、接口索引
  • 字段表集合
  • 方法表集合
  • 属性表集合

在开始之前,让我们写一个简单的介绍你好世界。接下来,我们将以Hello World文件的已编译字节码文件为例,解析字节码文件的内容。

public class Demo{
    public static void main(String args[]){
        System.out.println("Hello World.");
  }
}

然后运行javac Demo.命令行上的Java命令编译类,生成一个演示。类文件。

然后我们使用纯文本编辑器打开生成的Demo。类文件。

cafe babe 0000 0034 001d 0a00 0600 0f09
0010 0011 0800 120a 0013 0014 0700 1507
0016 0100 063c 696e 6974 3e01 0003 2829
5601 0004 436f 6465 0100 0f4c 696e 654e
756d 6265 7254 6162 6c65 0100 046d 6169
6e01 0016 285b 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 2956 0100 0a53 6f75
7263 6546 696c 6501 0009 4465 6d6f 2e6a
6176 610c 0007 0008 0700 170c 0018 0019
0100 0b48 656c 6c6f 2057 6f72 6c64 0700
1a0c 001b 001c 0100 0444 656d 6f01 0010
6a61 7661 2f6c 616e 672f 4f62 6a65 6374
0100 106a 6176 612f 6c61 6e67 2f53 7973
7465 6d01 0003 6f75 7401 0015 4c6a 6176
612f 696f 2f50 7269 6e74 5374 7265 616d
3b01 0013 6a61 7661 2f69 6f2f 5072 696e
7453 7472 6561 6d01 0007 7072 696e 746c
6e01 0015 284c 6a61 7661 2f6c 616e 672f
5374 7269 6e67 3b29 5600 2100 0500 0600
0000 0000 0200 0100 0700 0800 0100 0900
0000 1d00 0100 0100 0000 052a b700 01b1
0000 0001 000a 0000 0006 0001 0000 0001
0009 000b 000c 0001 0009 0000 0025 0002
0001 0000 0009 b200 0212 03b6 0004 b100
0000 0100 0a00 0000 0a00 0200 0000 0300
0800 0400 0100 0d00 0000 0200 0e

首先,需要明确字节码文件是以十六进制编码的,十六进制是以0x表示的,接下来,我们以“Hello World”的字节码文件为例,对这七个部分进行逐步的分析。

访问标志

在常量池的末尾,接下来的两个字节表示类或接口的access_flags。这里的数据是0021。

此标志用于标识类或接口级别的访问信息,包括类是类还是接口、是否定义为公共类型、是否定义为抽象类型等等。

类索引、父类索引、接口索引

在访问标记之后,它是类索引、父索引和接口索引的数据,其中数据是:0005000600。

类索引和父索引都是u2类型的数据,而接口索引集是一组u2类型的数据。这三个数据用于确定类文件中这个类的继承关系。

类索引。类索引用于确定该类的完全限定名称,该名称由类型u2的数据表示。这里的类索引是0005,表示它指向常量池中的第五个常量。根据前面的分析,我们知道第五个常量的最终信息是Demo类。

亲本索引。父索引用于确定该类的父类的完全限定名称,该名称由类型u2的数据表示。这里的父索引是0006,表示它指向常数池中的第六个常数。通过前面的分析,我们知道第六个常量的最终信息是Object类。因为它不继承任何类,所以Demo类的父类是默认的对象类。

接口索引。接口索引集用于描述哪些类实现哪些接口,这些接口索引集按照实现语句之后的接口顺序从左到右排列(如果类本身是接口,那么它应该是扩展语句)。对于接口索引集,第一个条目是作为interface_count的U2类型数据,它表示索引表的容量,后面跟着所有接口信息。如果类没有实现任何接口,则计数器值为0,并且后一个接口的索引表不占用任何字节。
在Demo类的字节码文件中,因为没有实现接口,所以紧跟在父类索引之后的两个字节是0x0000,这意味着该类没有实现任何接口。所以下面的接口索引表是空的。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java程序员-张凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值