栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

请总结一下Class 文件结构?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

请总结一下Class 文件结构?

根据 Java 虚拟机规范,类文件由单个 ClassFile 结构组成:

ClassFile {    u4  magic; //Class 文件的标志    u2  minor_version;//Class 的小版本号    u2  major_version;//Class 的大版本号    u2  constant_pool_count;//常量池的数量    cp_info        constant_pool[constant_pool_count-1];//常量池    u2  access_flags;//Class 的访问标记    u2  this_class;//当前类    u2  super_class;//父类    u2  interfaces_count;//接口    u2  interfaces[interfaces_count];//一个类可以实现多个接口    u2  fields_count;//Class 文件的字段属性    field_info     fields[fields_count];//一个类会可以有个字段    u2  methods_count;//Class 文件的方法数量    method_info    methods[methods_count];//一个类可以有个多个方法    u2  attributes_count;//此类的属性表中的属性数    attribute_info attributes[attributes_count];//属性表集合}

下面详细介绍一下 Class 文件结构涉及到的一些组件。

Class文件字节码结构组织示意图 (之前在网上保存的,非常不错,原出处不明):

2.1 魔数

    u4  magic; //Class 文件的标志

每个 Class 文件的头四个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接收的 Class 文件

程序设计者很多时候都喜欢用一些特殊的数字表示固定的文件类型或者其它特殊的含义。

2.2 Class 文件版本

    u2  minor_version;//Class 的小版本号    u2  major_version;//Class 的大版本号

紧接着魔数的四个字节存储的是 Class 文件的版本号:第五和第六是次版本号,第七和第八是主版本号

高版本的 Java 虚拟机可以执行低版本编译器生成的 Class 文件,但是低版本的 Java 虚拟机不能执行高版本编译器生成的 Class 文件。所以,我们在实际开发的时候要确保开发的的 JDK 版本和生产环境的 JDK 版本保持一致。

2.3 常量池

    u2  constant_pool_count;//常量池的数量    cp_info        constant_pool[constant_pool_count-1];//常量池

紧接着主次版本号之后的是常量池,常量池的数量是 constant_pool_count-1(常量池计数器是从1开始计数的,将第0项常量空出来是有特殊考虑的,索引值为0代表“不引用任何一个常量池项”)。

常量池主要存放两大常量:字面量和符号引用。字面量比较接近于 Java 语言层面的的常量概念,如文本字符串、声明为 final 的常量值等。而符号引用则属于编译原理方面的概念。包括下面三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

常量池中每一项常量都是一个表,这14种表有一个共同的特点:开始的第一位是一个 u1 类型的标志位 -tag 来标识常量的类型,代表当前这个常量属于哪种常量类型.

类型标志(tag)描述CONSTANT_utf8_info1UTF-8编码的字符串CONSTANT_Integer_info3整形字面量CONSTANT_Float_info4浮点型字面量CONSTANT_Long_info5长整型字面量CONSTANT_Double_info6双精度浮点型字面量CONSTANT_Class_info7类或接口的符号引用CONSTANT_String_info8字符串类型字面量CONSTANT_Fieldref_info9字段的符号引用CONSTANT_Methodref_info10类中方法的符号引用CONSTANT_InterfaceMethodref_info11接口中方法的符号引用CONSTANT_NameAndType_info12字段或方法的符号引用CONSTANT_MothodType_info16标志方法类型CONSTANT_MethodHandle_info15表示方法句柄CONSTANT_InvokeDynamic_info18表示一个动态方法调用点

.class
文件可以通过
javap -v class类名
指令来看一下其常量池中的信息(
javap -v  class类名-> temp.txt
:将结果输出到 temp.txt 文件)。

2.4 访问标志

在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口,是否为 public 或者 abstract 类型,如果是类的话是否声明为 final 等等。

类访问和属性修饰符:

我们定义了一个 Employee 类

package top.snailclimb.bean;public class Employee {   ...}

通过

javap -v class类名
指令来看一下类的访问标志。

2.5 当前类索引,父类索引与接口索引集合

    u2  this_class;//当前类    u2  super_class;//父类    u2  interfaces_count;//接口    u2  interfaces[interfaces_count];//一个雷可以实现多个接口

类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于 Java 语言的单继承,所以父类索引只有一个,除了

java.lang.Object
之外,所有的 java 类都有父类,因此除了
java.lang.Object
外,所有 Java 类的父类索引都不为 0。

接口索引集合用来描述这个类实现了那些接口,这些被实现的接口将按

implents
(如果这个类本身是接口的话则是
extends
) 后的接口顺序从左到右排列在接口索引集合中。

2.6 字段表集合

    u2  fields_count;//Class 文件的字段的个数    field_info     fields[fields_count];//一个类会可以有个字段

字段表(field info)用于描述接口或类中声明的变量。字段包括类级变量以及实例变量,但不包括在方法内部声明的局部变量。

field info(字段表) 的结构:

  • access_flags: 字段的作用域(
    public
    ,
    private
    ,
    protected
    修饰符),是实例变量还是类变量(
    static
    修饰符),可否被序列化(transient 修饰符),可变性(final),可见性(volatile 修饰符,是否强制从主内存读写)。
  • name_index: 对常量池的引用,表示的字段的名称;
  • descriptor_index: 对常量池的引用,表示字段和方法的描述符;
  • attributes_count: 一个字段还会拥有一些额外的属性,attributes_count 存放属性的个数;
  • attributes[attributes_count]: 存放具体属性具体内容。

上述这些信息中,各个修饰符都是布尔值,要么有某个修饰符,要么没有,很适合使用标志位来表示。而字段叫什么名字、字段被定义为什么数据类型这些都是无法固定的,只能引用常量池中常量来描述。

字段的 access_flags 的取值:

2.7 方法表集合

    u2  methods_count;//Class 文件的方法的数量    method_info    methods[methods_count];//一个类可以有个多个方法

methods_count 表示方法的数量,而 method_info 表示的方法表。

Class 文件存储格式中对方法的描述与对字段的描述几乎采用了完全一致的方式。方法表的结构如同字段表一样,依次包括了访问标志、名称索引、描述符索引、属性表集合几项。

method_info(方法表的) 结构:

方法表的 access_flag 取值:

注意:因为

volatile
修饰符和
transient
修饰符不可以修饰方法,所以方法表的访问标志中没有这两个对应的标志,但是增加了
synchronized
native
abstract
等关键字修饰方法,所以也就多了这些关键字对应的标志。

2.8 属性表集合

   u2  attributes_count;//此类的属性表中的属性数   attribute_info attributes[attributes_count];//属性表集合

在 Class 文件,字段表,方法表中都可以携带自己的属性表集合,以用于描述某些场景专有的信息。与 Class 文件中其它的数据项目要求的顺序、长度和内容不同,属性表集合的限制稍微宽松一些,不再要求各个属性表具有严格的顺序,并且只要不与已有的属性名重复,任何人实现的编译器都可以向属性表中写 入自己定义的属性信息,Java 虚拟机运行时会忽略掉它不认识的属性。

参考

  • https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
  • https://coolshell.cn/articles/9229.html
  • https://blog.csdn.net/luanlouis/article/details/39960815
  • 《实战 Java 虚拟机》
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/362935.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号