JVM 字节码之常量池

214 阅读4分钟

一些名词解释,以及阅读字节码

常量池之前的内容

在上一篇的基础进行一些样例解释

  • 使用javap -verbose命令分析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类信息、类的构造方法、类中的方法信息类变量与成员变量等信息。
  • 魔数: 所有的.class字节码文件的前4个字节都是魔数,魔数值为固定值:0xCAFEBABE。 image.png

魔数你可以理解为标记,标记这是一个.class文件。


  • 魔数之后的4个字节为版本信息。 前两个字节表示minor version(次版本号),后两个字节表示major version(主版本号)。这里的版本号为00 00 00 34,换算成十进制,表示次版本号为0,主版本号为(3*16+4)52。说明,该文件的版本号表示为jdk的版本为∶1.8。 image.png

用版本号的原因:Java存在不同版本,方便VM进行版本识别,一般是向下兼容的,Java 8的VM可以运行Java 7写的代码,但是Java 7 的VM不一定可以运行Java 8写的代码,当JVM识别到版本高于当前版本时选择不执行。


常量池

  • 常量池(constant pool)紧接着主版本号之后的就是常量池入口。一个Java类中定义的很多信息都是由常量池来维护和措描述的,可以将常量池看作是Class文件的资源仓库,比如说Java类中定义的方法与变量信息,都是存储在常量池中。常量池中主要存储两类常量:字面量与符号引用。 字面量如文本字符串,Java中声明为final的常量值等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符等。

这里的常量并不是一定就是final 修饰的的变量,就public int a = 1;a就在常量池里面,它没有被final修饰。


  • 常量池的总体结构: Java类所对应的常量池主要由常量池数量与常量池数组(常量表) 这两部分共同构成。常量池数量紧跟在主版本号后面。占据2个字节;常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的元素的类型、结构都是不同的,长度当然也就不同;但是,每一种元素的第一个数据都是一个u1类型,该字节是个标志位,占据1个字节。JVM 在解析常量池时,会根据这个u1类型来获取元素的具体类型。值得注意的是,常量池数组中元素的个数=常量池数–1(其中0暂时不使用),目的是满足某些常量池索引值的数据在特定情况下需要表达 『不引用任何一个常量池』 的含义;根本原因在于,索引为0也是一个常量(保留常量),只不过它不位于常量表中,这个常量就对应null值;所以,常量池的索引从1而非o开始。
    image.png

    十六进制的18十进制就是(16+8)24,即常量池数组长度是24,用Javap 反编译一下看一看, image.png 这里只有23是因为上面提到的索引0是不使用的,是一个保留常量。

常量池类型结构

上面提到的常量池数量之后就是常量池数组,那到底在哪结束,无法直接确定,得慢慢分析,因为数组的类类型不一样,长度就不一样,下面举例说明一下,

  • 常量池类型结构表 image.png
  • 上面提到每种元素的都是1个字节的u1,

image.png

  • 用Javap 看看

image.png

以此类推,u几就是占几字节,就应该连续读几个字节。

  • 在JVM规范中,每个变量/字段都有描述信息,描述信息主要的作用是描述字段的数据类型、方法的参数列表〈包括数量、类型与顺序)与返回值。根据描述符规则,基本数据类型和代表无返回值的void类型都用一个大写字符来表示,对象类型则使用字符z加对象的全限定名称来表示。为了压缩字节码文件的体积,对于基本数据类型,JVM都只使用一个大写字母来表示,如下所示 :B- byte, C - char,D - double,F- float,I - int,J - long, S - short,Z - boolean,V - void,L-对象类型,如Ljava/ lang/String;

数组类型和方法描述

  • 对于数组类型来说,每一个维度使用一个前置的 [ 来表示,如int []被记录为[IString[][]被记录为[[Ljava/lang/String;
  • 用描述符描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组()之内,如方法:String getReaInamebyIdAndNickname(int id,string name)的描述符为:( I,Ljava/lang/String;) Ljava/lang/String;

描述符中没方法名,是因为方法名在常量池中。

image.png