spice and wolfspice and wolf Be the One you wanna Be

Class字节码文件详解

文件结构

魔数:class标识

副版本号:java主版本下的细分版本信息。运行时版本号要大于等于编译时版本号,否则会报错。

主版本号:java主版本号。运行时版本号要大于等于编译时版本号,否则会报错。

常量池计数器:存储常量池的字节长度。

常量池数据区:存储常量数据。

访问标志:存储类的访问标志,如public、private

类索引:存储类的符号索引。

父类索引:存储父类的符号索引。

接口计数器:存储接口信息数据区的字节长度。

接口信息数据区:存放接口数据。

字段计数器:存储字段信息数据区字节长度。

字段信息数据区:存储字段数据。

方法计数器:存储方法信息数据区字节长度。

方法信息数据区:存储方法数据。

属性计数器:存储属性信息数据区字节长度。

属性信息数据区:存储方法体。

class常量池如何存储数据

常量池的常量有哪些?

字面量和符号引用

常量池结构

常量池计数器是从1开始计数的,不是从0开始计数,最后一个常量池项的索引值为constant_pool_count-1(出于特殊考虑,为了表示”不引用任何一个常量池项”的目的,遂将0号索引空出来,这种情况下会将索引值设置成0)

常量池项结构

tag值和类型对应关系如下:

constant_utf8_info、constant_integer_info、constant_long_info、constant_float_info、constant_double_info都是字面量结构体,而其他的都是引用结构体。

如何存储String类型的字符串常量?

字符串常量”JVM字符串”的字节码存储结构

如何存储类Class引用类型

class类com.jvm.ClassTest的字节码存储结构

哪些类型字面量会进入到常量池中?

  • final修饰时,8种基本类型
  • 没有final修饰时,double、float、long
  • 常量池中包含的字符串类型字面量(双引号引起来的字符串)

符号引用和直接引用

符号引用(class文件中)

在java中,一个java类将会编译成一个class文件。在编译时,java类并不知道索引用的类的实际地址(内存地址),因此只能使用符号引用来代替。

直接引用(运行时内存中)

直接引用可以是:

  • 直接指向目标的指针
  • 相对偏移量
  • 一个能间接定位到目标的句柄

引用替换时机

  • 类加载的解析阶段进行替换
  • 运行期间

class中的特殊字符串

特殊字符串包括三种:类的全限定名、字段和方法的描述符,特殊方法的方法名。

类的全限定名

源文件中一个类的名字是用全限定名表述的。比如Object类,在源文件中的全限定名表示为java.lang.Object,而class文件中则是将”.”替换成”/”,也就是java/lang/Object。

描述符

  • 8种基本数据类型:除了long和boolean,都是大写首字母表示,long则是J,boolean是Z
  • void描述符是V。
  • 对象类型:L加全限定名表示。如String的描述符为Ljava/lang/String。
  • 数组类型:每增加一个维度则在对应的字段描述符前增加一个[。如String[][]的描述符为[[Ljava/lang/String。
字段描述符

字段描述符就是字段类型对应的字符或字符串。如int i的描述符就是I,String o的描述符就是Ljava/lang/Object

方法描述符

方法描述符包括所有参数的类型列表和方法返回值。格式如下:

(参数1类型 参数2类型 参数3类型 …)返回值类型。如int getSize()的描述符为()I,int read(byte[] b, int off, int len)的描述符为([BII)I。

特殊方法的方法名

  • 类的构造方法用<init>表示
  • 静态初始化方法用<clinit>表示

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Press ESC to close