JVM学习笔记- 4 类文件结构

JVM学习笔记- 4 类文件结构

1.Java跨平台?

Java是编译性语言,具有跨平台性。因为Java执行需要将.java编译成字节码文件.class。而各个平台的虚拟机载入和执行平台无关性的字节码文件。(Java虚拟机只关心class文件。而不关心class文件是怎么来得(Groovy,JPython,JRuby编译生成的class文件))。

2.class文件结构

Java执行需要.java文件通过javac 命令编译成.class文件。在通过java 命令执行.class文件。而class文件里存储的是以8位字节为基础单位的二进制流。中间没有任何符号分隔符。
class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表

  • 无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。
  • 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。
    class文件格式
    class文件格式
    注:class文件中的数据项,无论是顺序还是数量,都是被严格限定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变。
    eg:以Test类为例
    public class Test{ private int id; public Test(int id){ this.id = id; } public int getId(){ return id; } public void setId(int id){ this.id = id; } }
    Test.class文件用WinHex打开
    16进制
2-1.魔数与Class文件的版本

Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。
第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。

eg:从图中可以看到 03(u4)为魔数,45(u2)为次版本号,6~7为(u2)为主版本号

2-2.常量池

常量池中主要存放两大类常量:字面量和符号引用。字面量比较接近于Java语言层面的常量概念,如文本字符串、声明为final的常量值等。符号引用则属于编译原理方面的概念,包括了下面三类常量:类和接口的全限定、字段的名称和描述符、方法的名称和描述符。
常量池项目类型
常量池项目类型
常量池中每一项常量都是一个表
常量池表项目结构1
常量池表项目结构2

eg: 8~9 为u2长度的constant_pool_count值为0015 ,十进制为21,代表常量池中有20个常量,下标为1-20(因为常量池设计时将下标0常量空出来)。

cp1:接下来第一个字节为0A十进制为10 为类中方法符号引用,查看类中方法符号引用结构可知第一个u2指向声明方法的类描述符CONSTANT_Class_info索引项。第二个u2指向名称及类型描述符CONSTANT_NameAndType索引项。

cp2:第二个常量的tag为09 是字段符号引用,查看字段符号引用结构之第一个u2指向声明字段的类描述符CONSTANT_Class_info索引项。第二个u2指向字段描述符CONSTANT_NameAndType索引项。

cp3:第三个常量的tag为07 是Class_info 类或接口的符号引用。结构为tag-u1 ,index -u2 类的全限定名常量池的引用。index 值为0012 十进制为18,指向第18个常量。

cp4:第四个常量也是tag为07的Class_info符号引用。index为0013 十进制为19,指向第19个常量。

cp5:第五个常量的tag为01 为Utf8_info(UTF8的字符串)结构为tag-u1,length-u2,bytes-length。 length值为0002 ,说明此常量长度为两个字节,紧跟着length的后两个字节为常量的值 6964 ascii编码为id.

通过javap -v Test.class命令可以查看到所有的常量
常量池

2-3.访问标志

紧接着的两个字节代表访问标志(access_flags),这个标志用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等
类访问标示
eg: class文件中access_flags值为0021 ACC_SUPER|ACC_PUBLIC

2-4.类索引、父类索引与接口索引集合

类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集
合(interfaces)是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的继承关系。
类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。
由于Java语言不允许多重继承,所以父类索引只有一个,除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0。接口索引集合就用来描述这个类实现了哪些接口,这些被实现的接口将按implements语句(如果这个类本身是一个接口,则应当是extends语句)后的接口顺序从左到右排列在接口索引集合中。

eg: class文件中 权限标示的后六位为 0003 0004 0000所以this_class指向常量池中的第三个,super_class指向第四个,interfaces_count 为0000则说明没有实现接口。

2-5.字段表集合

字段表(field_info)用于描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。字段的作用域(public、private、protected修饰符)、是实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile修饰符,是否强制从主内存读写)、可否被序列化(transient修饰符)、字段数据类型(基本类型、对象、数组)、字段名称。上述这些信息中,各个修饰符都是布尔值,要么有某个修饰符,要么没有,很适合使用标志位来表示。而字段叫什么名字、字段被定义为什么数据类型,这些都是无法固定的,只能引用常量池中的常量来描述。
字段表结构
字段访问标示
描述符含义

eg: 从class文件中可知 field_counts 为0001 有一个字段 access_flags 为 0002 字段是私有字段。name_index(简单名称) 为0005 指向常量池中第五个符号引用 (id)descriptor_index(描述符) 为 0006 指向常量池中第六个符号引用 (I) id为int类型
attributes_count 为0000 没有属性

2-6.方法表集合

方法表结构
方法访问标志
注:方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为“Code”的属性里面,属性表作为Class文件格式中最具扩展性的一种数据项目.

eg:methods_count为0003(三个方法),access_flags为0001(ACC_PUBLIC),name_index为 0007 指向常量池第7个常量 descripter_index 为 0008 指向第8个常量,attributes_count 为 0001 有一个属性

2-7.属性表集合

属性表,在Class文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。它的名称需要从常量池中引用一个CONSTANT_Utf8_info类型的常量来表示,而属性值的结构则是完全自定义的,只需要通过一个u4的长度属性去说明属性值所占用的位数即可。
属性表项目比较多,只列出几个为例
code属性
code属性

eg:class文件方法的属性表中属相attribute_name_index 为0009 指向常量池中第九个常量,“Code”。后面的u4 为0000002A attribute_length 长度为42,
max_stack代表了操作数栈(Operand Stacks)深度的最大值 0002
max_locals代表了局部变量表所需的存储空间 0002
code_length 代表字节码长度 0000000A 长度为10
code 字节码指令为 2A B7 00 01 2A 1B B5 00 02 B1
exception_table_length 为 0000 没有 异常信息
attributes_count 为 0001 说明还有一个属性信息
attributes_name_index 为 000A 指向第10个常量 LineNumberTable

Code属性是Class文件中最重要的一个属性,如果把一个Java程序中的信息分为代码(Code,方法体里面的Java代码)和元数据(Metadata,包括类、字段、方法定义及其他信息)两部分,那么在整个Class文件中,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。

此博客为学习Java虚拟机笔记。如有不详细的地方请查看“深入理解Java虚拟机 JVM高级特性与最佳实践(第二版)”

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值