第三部分-class文件结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jtracydy/article/details/80147541

嘚不嘚:这个篇幅的内容是结构的介绍,类似与学习Map的结构是差不多的,每个部分是什么意思,代表着什么,这部分更倾向于理解记忆。

概述
  1. 平台无关性:一次编译到处运行,说的是java是跨平台的,同样的java代码在linux平台可以运行,在windows平台也可以运行,这一切都归功与class文件的结构,它是一个固定的结构,该结构的每一部分都有严格的规定。JVM是运行在操作系统之上的,而JVM是能够识别class文件的。
  2. 语言无关性:只要能编译成class文件结构的语言,都是可以运行在JVM之上的。
class文件结构
  1. 概述:每个类或者接口都对应着唯一的一个class文件,而class文件结构不一定对应着类和接口,类或者接口可以通过类加载器生成。
    1. 基本定义:
      1. 完全限定名:一个 ClassTest的类,并把它放到com.louis.jvm 包下,则 ClassTest类的完全限定名为com.louis.jvm.ClassTest。
      2. 二进制形式完全限定名:com/louis/jvm/ClassTest。
  2. 两种类型的数据结构:
    1. 无符号数:基本数据类型,u1、u2代表一个字节、两个字节,无符号数可以用来描述数字、索引引用、数字等。
    2. 表:由无符号数和表组成的。
  3. 魔术和版本:
    1. 魔术:4个字节,确定这个文件能否被class文件识别。“oxCAFEBABE”
    2. 版本:四个字节,前两个字节表示次版本号,后两个字节表示主版本号。
  4. 常量池:

    1. 概述:因为类中的方法和属性不是固定的,所以常量池的数量也不是固定的,类中的方法和属性都会在编译之后的静态结构都会在常量池中,这些静态的结构只有在加载到JVM中才能转化为可以被调用的结构。因为类和方法的数量都是不固定的,所以常量池的大小也不是固定的。
    2. 常量池结构:在常量池的入口处是一个u2类型的数据,代表常量池容量计数器,也就是代表了常量池中常量的数量。常量池中的常量是从第1个位置开始的,假如常量池容量计数器的值为22,那么表示常量池中有21个常量,从1-21表示为类中常量。第0个位置的设计是处于其他考虑的,如果某个数据不引用常量池中的任何常量那么它指向常量池中第0个位置。
    3. 两大类型常量:
      1. 字面量:基本数据类型在javac之后转化为字面量,final修饰的字符串类型也是字面量。
      2. 符号引用:
        1. 类和结构的全限定名
        2. 字段的名称和描述符
        3. 方法的名称和描述符
    4. 表结构:表的第一位是u1类型得标志位,12种表结构中分为如下的三个类别,一个类别是字面量(表结构:标志位+数据)、一个类别是引用(表结构:标志位+所属类+具体数据–>表)、另一个类别是为了支持动态语言的。前两个类型的表结构各介绍一种。
      这里写图片描述

      1. 字面量(CONSTANT_Integer_info, CONSTANT_Float_info)参考博客

        1. 结构图:
          这里写图片描述
        2. CONSTANT_Integer_info表第一位标识该变量的类型,bytes表示该字面量的数据。在javac的过程中,对于字面量是存在优化的,如果在一个类中存在多个值为10的int类型的数据,在class文件中会再存一个值为10的变量,其他的值均指向该变量。
      2. 符号引用
        (CONSTANT_Fieldref_info, CONSTANT_Name_Type_info)参考博客

        1. 结构图:
          这里写图片描述
        2. CONSTANT_Fieldref_info:通常在调用类的方法和使用类的属性时,通常都是初始化类的对象,然后通过对象调用类的方法和使用类属性值。tag:标识表的类型,name_index:标识所属类的类型,name_and_type_index:标识该属性的类型和属性的名称,同时指向另外的一个表结构。
        3. CONSTANT_Name_Type_info:name_index:标识属性的名称,descriptor_index:标识属性的类型。
      3. 在编写代码的时,经常会出现初始化其他类的对象,在ClassTest类中声明了一个Date对象,同时date引用指向改对象。
package com.jvm;  
import  java.util.Date;  
public class ClassTest {  
    private Date date =new Date();  
}  

这里写图片描述

在常量池中描述了类、接口、类方法、属性等信息,但是对于类的某个方法或者属性信息,不光包括方法的名字、方法的参数和方法的返回值类型,还包括类的访问权限修饰符、方法的局部变量和方法的逻辑等内容,因此在常量池后面紧接着介绍了关于类的访问权限、该类的父类或者实现类等信息。
5. 访问标志:常量池结束后的两个字节代表类的访问标志,class是类还是接口、是否定义为public、是否定义为abstract、如果是类是否呗final修饰等。
6. 类索引、父类索引与接口索引集合:因为类是单继承,多实现,在类的访问标志之后,存在一个u2数据类型的类索引,一个u2类型的父类索引,一组u2类型的接口索引,其实就是存在多个constant_class_info类型的符号引用,通过这些符号引用找到类的二进制完全限定名。
7. 字段表集合:描述类或者接口中声明的变量,字段包括类级变量以及实例变量。字段应该包括的信息:字段的作用域、是类变量还是实例变量、可变性、并发可见性、字段数据类型、字段名称等。
8. 方法表集合:方法表同字段表,依次包括了:访问标志、名称索引、描述符索引、属性表集合。
9. 属性表集合:在class文件中、字段表、方法表都可以携带自己的属性表集合,例如:方法内部的代码、异常信息等。(属性比较多,只介绍一部分)
10. Code属性:java程序方法体中的代码经过javac编译后处理后,最终变为字节码属性存储到code属性内。如果方法不存在方法体,那么就不存在code属性。
11. 属性:
12. ttribute_name_index:属性名称
13. attribute_length:属性长度
14. max_stack:代表了操作数栈的最大深度,由该值确定栈帧中操作数栈的大小
15. max_local:局部变量表所需要的存储空间,下面是局部变量表中的内容,方法参数、异常处理器参数、局部变量。
16. code_length和code:字节码长度和字节码指令。
17. exception_table_length:显示异常处理表集合,异常表格式说明异常的捕获的位置和异常发生后,处理异常的位置。

猜你喜欢

转载自blog.csdn.net/jtracydy/article/details/80147541