zoukankan      html  css  js  c++  java
  • JVM-Class文件的结构

    Class类文件的结构

    Class文件是一株以8个字节为单位的二进制流。各个数据项目严格按照顺序紧凑的排列在文件之中,中间没有任何的分隔符,当遇到占用的空间大于8个字节时,会按照高位在前的方式进行分割,分割单位还是8个字节。

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

    • 无符号数:属于基本的数据类型,以u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数,他可以用来描述索引,数字,数量值或者按照utf8彪马构成字符串值。
    • 表:属于复合数据类型,是由多个基础类型或者表组合而成。为了区分表和基础数据类型,通常表的命名都是以“_info”结尾的。表示描述的是具有层次关系的数据。整个Class文件本质上也可以看做是一张表。
    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文件的前四个直接被称为魔数。

    作用:确定这个文件是否是一个被虚拟机接收的Class文件。

    为什么不是用文件的扩展名来进行虚拟机的识别标志?

    因为文件的扩展名可以被用户随意更改。但是魔数是嵌入在文件头的,不会改变。

    Class文件的版本号:紧跟魔数后边的四个字节,这四个字节中前两个字节是次版本号,后两个是主版本号。高版本可以兼容低版本的Class文件。

    注意:可以使用WinHex软件打开Class文件,查看分析字节对应的内容。

    image-20200824171832168

    常量池

    常量池:紧接着主次版本号,u2,两个字节表示常量池的数量,从1开始计算,原因是将第0项空出来表示不引用常量池中任何项目。是与其他项目关联最多的数据类型,也是Class文件空间中最大的项目。

    常量池主要存放两种常量:字符量和符号引用。

    字符量:如字符串,声明时final类型的变量等。

    符号引用:属于编译原理上的概念,包括三种,类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。

    常量池中的每一项都是一个表,17种表中,表开始的第一位是一个u1类型的标志位,代表当前这个常量属于哪种常量类型。

    image-20200825224259239

    image-20200825224324207

    Java程序中如果定义了超过64kb英文的字符的变量或方法名,将会无法编译。

    javap:一个专门用于分析Class文件的字节码工具,可以通过-verbose参数输出的.class文件内容。

    访问标志

    在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息,包括这个Class是类还是接口,访问权限是public还是private,是否是abstract,是否被final修饰等。

    image-20200825225804598

    类索引与接口索引集合

    类索引和父类索引都是u2类型的数据,而接口索引是一组u2类型的集合,Class文件通过这三种数据来确定类的继承关系。

    类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。

    接口索引就是用来描述这个类实现了哪几种接口。集合中的顺序是按照implements后面的接口顺序。

    类索引,父类索引,接口索引都是按照顺序排列在访问标志之后。

    类索引和父类索引的索引值指向了一个类型是CONSTANT_Class_info的类描述符常量。这个常量的值又指向了CONSTANT_Utf8_info类型的全限定名 字符串。(全限定名例如:org/fenixsoft/clazz/TestClass;其实就是将 “.” 换成“/”)

    image-20200825230637228

    对于接口索引集合,入口的第一项u2类型的数据为接口计数器(interfaces_count),表示索引表
    的容量。如果该类没有实现任何接口,则该计数器值为0,后面接口的索引表不再占用任何字节。

    字段集合

    字段表:用于描述接口或者类中声明的变量。Java中的字段不包括方法内部的局部变量。

    字段表结构

    image-20200825230950117

    access_flag:字段的作用域

    image-20200825231831212

    name_inedx:对常量池的引用,表示字段名称。

    descriptor_index:对常量池的引用,表示字段和方法的描述符,用来描述字段的数据类型,方法的参数列表和返回值。

    image-20200825231458917

    attribute_count:表示额外属性字段。

    attributes:表示具体属性。

    方法集合

    方法表结构和字段表结构差不多,依次是访问标志,名称索引,描述符索引,属性表集合

    image-20200825232000441

    方法访问标志

    image-20200825232032021

    Java方法中的具体代码在属性表集合中的一个叫做Code的属性里面。

    与字段表集合相对应地,如果父类方法在子类中没有被重写(Override),方法表集合中就不会出
    现来自父类的方法信息。

    重载方法为什么不能依靠返回值来判断?

    特征签名:指一个方法中各个参数在常量池中的字段符号引用的集合。

    也正是因为返回值不会包含在特征签名之中,所以Java语言里面是无法仅仅依靠返回值的不同来对一个已有方法进行重载的。

    属性表集合

    字段表、方法表都可以携带自己的属性集合,用来描述某种场景的专有信息。

    属性表集合对属性的顺序没有要求,只是不允许有重复的属性名。

    集合中的每一个属性,它的名称都要从常量池中引用一个CONSTANT_Utf8_info类型的常量来表示,而属性值的结构是自定义的。

    image-20200826152853647

    属性列表

    image-20200826152954990

    image-20200826153058491

    image-20200826153119733

  • 相关阅读:
    阿里云ECS网站备案流程
    python学习之os.walk()
    python学习之pypandoc
    linux下的which
    python学习之range()和xrange()
    Python内置函数之repr()
    python学习之字典
    SQL基础之聚合与排序
    SQL基础教程
    lombok的安装
  • 原文地址:https://www.cnblogs.com/itjiangpo/p/14181334.html
Copyright © 2011-2022 走看看