Java类文件 常量池

Java类文件中的常量池(Constant Pool)是类文件中的一个重要部分,它保存着字面量和符号引用等信息,用于支持代码执行。在Java虚拟机运行时,常量池中的信息会被加载到内存中,并转换为实际的数据类型。常量池是类文件中较为复杂的结构之一,包含多种数据类型和结构。

常量池中包含的数据类型有:

字面量(Literal):如整型、浮点型、字符串等
符号引用(Symbolic Reference):包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符等
类型描述符(Descriptor):描述字段、方法参数和返回值的数据类型
常量池中的数据结构主要有两种:CONSTANT_xxx_info和CONSTANT_InvokeDynamic_info。前者表示常量池中的常量,包括字面量和符号引用等,后者用于支持Java SE 7中的InvokeDynamic指令。

下面是一个常量池的例子:

Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = String             #16            // Hello, world!
   #3 = Fieldref           #17.#18        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #21            // HelloWorld
   #6 = Class              #22            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               HelloWorld.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = Utf8               Hello, world!
  #17 = Class              #23            // java/lang/System
  #18 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;
  #19 = Class              #26            // java/io/PrintStream
  #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V
  #21 = Utf8               HelloWorld
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/String;)V

上面的例子是一个简单的HelloWorld程序的常量池,它包含了类中用到的各种字面量、符号引用和类型描述符等。我们可以看到,每个常量都有一个编号,这个编号可以被其他常量引用。常量池的编号从1开始,到常量池大小-1为止”是指常量池中每个项目的编号,而不是指常量池中所有项目的总数。在Java 11及以前的版本中,常量池中的项目数量是16位无符号整数,因此最多可以有65535个项目,编号从1到65534。

在Java 11中,JEP 333 引入了一个新的常量池形式,称为“condy常量池”,这使得常量池中可以包含动态生成的常量,从而提高了JVM的灵活性和性能。由于condy常量池具有不同的结构,因此它的编号方式与普通常量池略有不同。