• Class文件结构


    结构总览

    -w851

    Class文件中只有两种数据类型:无符号数和表:

    • 无符号数:属于基本的数据类型,以u1,u2,u4,u8代表对应的字节数;
    • 表:是由多个无符号数或者其他表作为数据项组合而成的复合数据结构。

    1.magic(u4)

    魔数,固定为0xCAFEBABE,唯一的作用是确定这个文件是否为一个能被虚拟机接受的class文件;

    2.minor_version(u2) 和 major_version(u2)

    minor_version:class文件次版本号;
    major_version:class文件主版本号

    3.constant_pool_count(u2) 和 constant_pool(cp_info)

    由于常量池的数量是不固定的,所以需要在前面放置一个constant_pool_count(u2)表示常量池的数量(注意常量池的计数是从1开始的,设计者将第0项空出来是为了满足后面要表示“不引用任何一个常量池项目”)。

    常量池主要存放两大类常量:

    • 字面量:比如文本字符串,声明为final的常量值,文件名等;
    • 符号引用:类和接口的全限定名;字段的名称和描述符;方法的名称和描述符.

    Java代码在进行Javac编译的时候,并不像C和C++那样有“连接”这一步骤,而是在虚拟机加载Class文件的时候进行动态连接,根据实际运行的类型将对应的符号引用解析成具体的内存地址;也就是说,在Class文件中不会保存各个方法、字段的最终内存布局信息。

    -w803

    4.access_flags(u2)

    类或接口的访问标志,包括:

    • 这个Class是类还是接口?
    • 是否public?
    • 是否abstract?
    • 是否final?

    -w900

    5.this_class(u2) 和 super_class(u2)

    • this_class:类索引;
    • super_class:父类索引;
      这两个索引都会指向常量池中类型为CONSTANT_Class_info,其中Object类的super_class为0。

    6.interfaces_count(u2) 和 interfaces

    • interfaces_count表示接口数量;
    • interfaces是接口的集合,内部每个条目是u2类型指向常量池;

    7.fields_count(u2) 和 fields

    -w909

    • access_flags表示一些访问标识符
      -w884

    • name_index 表示字段的名称,指向常量池的下标;

    • descriptor_index 表示字段描述符,指向常量池的下标;
      -w901

    • attributes_count(u2) 和 attributes
      字段的属性集合,可以存储一些额外的信息,可以包含零个或多个;
      由于在Class级别也有attributes属性,后面再详细介绍。

    8.methods_count(u2) 和 methods

    方法的描述和字段的描述采用了一样的结构,如下所示:

    -w895

    和字段表不同的是,access_flags的取值不同,因为volatile和transient不能修饰方法,所以方法的access_flags中没有ACC_VOLATILE和ACC_TRANSIENT,同时方法相对于字段多了Synchronized、native、abstract等,所以多了ACC_SYNCHRONIZED、ACC_NATIVE、ACC_ABSTRACT等值.

    -w882

    还有一个最大的区别是:字段表的attribute里面多了一个Code字段;
    方法体中的代码经过Javac编译后,最终变为字节码存储到Code属性内;只有拥有方法体的方法才会有Code属性,接口的方法和抽象方法是没有的。

    -w905

    这里介绍主要的属性:

    • max_stack:表示操作数栈(Operand Stacks)的最大深度,虚拟机运行的时候需要根据这个值栈帧(Stack Frame)中的操作数栈深度;
    • max_locals:表示局部变量表所需的空间,max_locals的单位是Slot
      Slot是虚拟机为局部变量分配内存所使用的最小单位;
      对于byte、char、float、int、short、boolean、returnAddress等长度不超过32位的数据类型,每个局部变量占用1个Slot;
      对于double和long这两种64位的数据类型占2个Slot。
      

    方法参数(包括实力方法中的隐藏参数this)、try-catch语句中的catch块中所定义的异常、方法体中定义的局部变量都需要存放在局部变量表里面;
    值得注意的:max_locals的值并不等于上述各项之和,原因是局部变量表中的Slot是可以重用的,当代码执行超出一个变量的作用域时,这个局部变量所占的Slot可以被其他局部变量使用。

    • code:用来存储编译后生成的字节码指令,每个指令就是一个u1类型的数据;
      字节码所对应的指令含义是虚拟机事先定义好的,当虚拟机读取到code中的一个字节码时,就可以找出对应的指令,配合操作数栈完成指令内容。

    • exception_table:用来表示显示的异常处理表,对应于代码中的try-catch语句;
      异常表实际上是Java代码的一部分,编译器使用异常表而不是简单的跳转命令来实现Java异常及finally处理机制;
      -w901
      其中包括了4个字段,表示含义为:虚拟机在执行字节码的时候,如果在[start_pc,end_pc)行之间出现了catch_type的异常,则程序会跳转到handler_pc行继续处理;
      当catch_type的值为0时,代表除了catch_type的任意异常情况都要跳转到handler_pc处继续进行。

    • Exceptions:表示方法可能抛出的异常;
      这里的Exceptions属性是在方法表中与Code属性平级的,不是上面的exception_table;

    9.attributes属性

    该属性可用的选项比较多,常用的有:

    • LineNumberTable:用于描述Java源代码和字节码行号的对应关系,不是运行时必须的;
    • LocalVariableTable:用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,不是运行时必须的;
    • SourceFile:Class文件的源码文件的文件名称;
  • 相关阅读:
    浏览器操作本地缓存记录一下
    dotnet new Getting ready... Object reference not set to an instance of an object.
    IIS上vue打包后接口跨域解决
    SpringBoot前言
    Node聊天室和socket.io原理与功能总结
    Node加解密原理和功能探索总结
    Node中文件断点续传原理和方法总结
    Node短链原理与功能实现总结
    Node中F2A原理及功能实现总结
    Node图形邮箱手机验证码实现方法总结
  • 原文地址:https://www.cnblogs.com/monsterdev/p/12685116.html
Copyright © 2020-2023  润新知