文章目录

  • 1 class 文件概述
  • 2 魔数
  • 3 文件版本号
  • 4 常量池
  • 5 访问标识
  • 6 类索引,父类索引,接口索引集合
  • 7 字段表
  • 7.1 字段表结构
  • 8 方法表集合
  • 8.1 方法表结构
  • 9 属性表集合


1 class 文件概述

  • 字节码文件是什么

字节码是一种二进制的类文件,其内容是jvm的指令。

  • 什么是字节码指令

jvm指令是由某种特定操作的操作码与此操作所需的参数的操作数构成的

  • Class类的本质

任何一个class文件都对应这唯一 个类或接口的定义信息(并不一定以磁盘形式存在),class文件是以8位字节为基础单位的二进制流

  • class文件格式

有两种数据类型:无符号数和表

  • 无符号数属于基本的数据类型,以u1,u2,u4,u8,来代表1个字节,2个字节,4个字节和8个字节,无符号数用来描述数字,索引引用,数量值
  • 表是由多个无符号数和其他表构成的复合数据类型,所有表都习惯性地以“_info" 进行结尾。
  • class 文件的总体结构
  • 魔数
  • class文件版本
  • 常量池
  • 访问标志
  • 类索引,父类索引,接口索引集合
  • 字段表集合(类变量)
  • 方法表集合
  • 属性表集合(类名等信息)

2 魔数

由于文件的后缀名可以随便改,设置class文件开头的魔数 cafebabe来进行校验,是否是一个合格的字节码校验文件。

3 文件版本号

不同版本的java编译器编译的class文件对应的版本是不一样的。目前高版本的jvm可以执行由低版本编译器生成的class文件,但是低版本的jvm不能执行由高版本编译器生成的class文件


4 常量池

  • 常量池主要存放两大类常量:字面量符号引用

class字节码转java_数据类型

  • 字面量:
  • 字符串常量
  • 被final修饰的变量
  • 符号引用:
  • 类和接口的全限定名
  • 字段名称和描述符
  • 方法的名称和描述符

注意: com/ws/Test 就是类的全限定名,仅仅是把 包名的“.”替换成了“/”,简单名称是指没有类型和参数修饰的方法或者字段名称描述符的作用是用来描述字段的数据类型,方法的参数列表(包括数量,类型,以及顺序)和返回值

描述符所展示的数据类型

class字节码转java_jvm_02


  • 补充说明:

虚拟机在加载class文件时才会进行动态链接,因此这些字段和方法的符号引用不经过转换时无法被使用的,当jvm运行时,需要从常量池中获得对应的符号引用,在类加载过程中的解析阶段将其替换为直接引用,并翻译到具体的内存地址。

  • 符号引用:符号引用是以一组符号来描述所引用的目标,符号引用与虚拟机实现的内存布局无关。
  • 直接引用:是直接指向目标的指针,相对偏移量或是直接定位到目标的句柄,直接引用是与虚拟机实现的内存布局相关。
  • 常量池中所存储的详细信息

class字节码转java_class字节码转java_03

class字节码转java_class字节码转java_04

  • 常量池中为什么要包含这些内容

java代码进行javac编译时,并不会有“连接”步骤,而是在虚拟机加载 class文件是进行动态链接,在class文件中不会保存各个方法,字段的最终内存布局信息,当虚拟机运行时,需要从常量池获得对应的符号引用,在类创建时进行解析,翻译到具体内存地址。

5 访问标识

访问标识是用于识别一些类或者接口层次的访问信息,包括这个class文件是类还是接口,是否被定义为 public类型,final,abstract等。

class字节码转java_class字节码转java_05

6 类索引,父类索引,接口索引集合

这三项数据确定了这个类的继承关系

  • 类索引用于确定这个类的全限定名
  • 父类索引用于确定这个类的父类的全限定名
  • 接口索引集合用来描述这个类实现了哪些接口。

7 字段表

  • 用于描述接口或类中声明的变量。字段(field) 包括类级变量以及实例变量但不包括局部变量。
  • 字段的名称以及被定义的数据类型,引用常量池中的常量来描述
  • 它指向常量池索引集合,比如字段的标识符,访问修饰符,是类变量还是实例变量(static 修饰符),是否常量(final修饰符)

注意事项:

  • 字段表的集合中不会列出从父类或者实现的接口中继承的字段
  • 在java语言中字段是无法重载的,两个字段的数据类型,修饰符是否相同,都必须使用不一样的名称,但对于字节码,如果两个字段描述符不一致,则字段重名就是合法

7.1 字段表结构

字段表拥有以下结构

class字节码转java_数据类型_06

  • 字段表访问标识
    用于判断是否被各种关键字去修饰,作用域修饰(public,private,protected)static,final,volatile等

    class字节码转java_字段_07

  • 字段名索引

根据字段名索引,查询常量池中的指定索引。

  • 描述符索引

描述符的作用是用来描述字段的数据类型等也是通过查询常量池中的索引。

  • 属性表集合

一个字段还可能拥有一些属性,用于存储额外信息,比如初始化值(常量)

8 方法表集合

methods:指向常量池索引集合,它完整描述了每个方法的签名

  • 在字节码文件中,每个method_info都对应一个类或接口的方法信息。比如方法的访问修饰符,返回值,参数信息等。
  • 方法表只描述当前类或接口中声明的方法,不包括父类或父接口继承的方法,但methods有可能会出现编译器自动添加的方法,

注意事项:
在java语言中,要重载一个方法,除了要与原方法具有相同的名称外,还要求拥有与原方法不同的特征签名,特征签名就是一个方法中各个参数在常量池中的字段符号引用的集合,也就是返回值不在特征签名中。

8.1 方法表结构

class字节码转java_jvm_08

9 属性表集合

方法表集合之后的属性表结合,指的是class文件所携带的辅助信息
此外,字段表,方法表都可以有自己的属性表,用于描述某些场景专有的信息。