关于常量池和运行时常量池

3 篇文章 1 订阅


前言

最近在学习JVM运行时数据区中方法区的相关知识,其中涉及到常量池和运行时常量池,所以就把相关知识整理一下。

一、关于常量池

1.常量池是什么

常量池是字节码文件的一部分。JVM为每一个已经被加载的类型(类或者接口)都维护一个常量池,其中的数据项像数组项一样,通过索引访问。常量池中存储的数据类型:数量值、字符串值、类引用、方法引用、字段(属性)引用

java字节码文件中,除了包含类的版本信息、字段、方法以及接口等描述信息外,还包含常量池表(Constant Pool Table),在常量池表中包含了各种字面量和对类型、域(Field)、方法的符号的引用。

也就是说常量池中的数据以类似表的形式在常量池表中呈现,我们可以通过将编译后的字节码文件进行反编译来查看具体的内容,这里我们通过字节码查看工具jclasslib来查看。

2.查看常量池中的数据

代码源文件如下:

import java.util.Comparator;

public class ConstantPoolTest extends Object implements Comparator {
    public static void main(String[] args) {
        test1();
    }

    private static void test1() {
        int count = 20;
        System.out.println("count is:" + count);
    }

    @Override
    public int compare(Object o, Object t1) {
        return 0;
    }
}

我们对以上的ConstantPoolTest 类进行编译,通过jclasslib查看,下图显示的是test1方法的字节码,其中含有"#"的地方表示对常量池中结构的调用,引用到了常量池中的内容,“#”后的数字表示索引,通过它进行访问。
在这里插入图片描述可以看到,在istore_0执行完成后,int类型数据20倍存储到局部变量表中,随后,执行引擎执行到第3行时,需要用到常量池表中的第3项的内容, 点击“#3”可以看到该项具体的内容,显示此处需要用到System类,还需要调用#37和#38处的内容。
在这里插入图片描述
也可以通过 javap -v -p ConstantPoolTest 命令來查看:

Constant pool:
   #1 = Methodref          #12.#35        // java/lang/Object."<init>":()V
   #2 = Methodref          #11.#36        // jvm/ConstantPoolTest.test1:()V
   #3 = Fieldref           #37.#38        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = Class              #39            // java/lang/StringBuilder
   #5 = Methodref          #4.#35         // java/lang/StringBuilder."<init>":()V
   #6 = String             #40            // count is:
   #7 = Methodref          #4.#41         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #8 = Methodref          #4.#42         // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   #9 = Methodref          #4.#43         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #10 = Methodref          #44.#45        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #11 = Class              #46            // jvm/ConstantPoolTest
  #12 = Class              #47            // java/lang/Object
  #13 = Class              #48            // java/util/Comparator
  #14 = Utf8               <init>
  #15 = Utf8               ()V
  #16 = Utf8               Code
  #17 = Utf8               LineNumberTable
  #18 = Utf8               LocalVariableTable
  #19 = Utf8               this
  #20 = Utf8               Ljvm/ConstantPoolTest;
  #21 = Utf8               main
  #22 = Utf8               ([Ljava/lang/String;)V
  #23 = Utf8               args
  #24 = Utf8               [Ljava/lang/String;
  #25 = Utf8               test1
  #26 = Utf8               count
  #27 = Utf8               I
  #28 = Utf8               compare
  #29 = Utf8               (Ljava/lang/Object;Ljava/lang/Object;)I
  #30 = Utf8               o
  #31 = Utf8               Ljava/lang/Object;
  #32 = Utf8               t1
  #33 = Utf8               SourceFile
  #34 = Utf8               ConstantPoolTest.java
  #35 = NameAndType        #14:#15        // "<init>":()V
  #36 = NameAndType        #25:#15        // test1:()V
  #37 = Class              #49            // java/lang/System
  #38 = NameAndType        #50:#51        // out:Ljava/io/PrintStream;
  #39 = Utf8               java/lang/StringBuilder
  #40 = Utf8               count is:
  #41 = NameAndType        #52:#53        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #42 = NameAndType        #52:#54        // append:(I)Ljava/lang/StringBuilder;
  #43 = NameAndType        #55:#56        // toString:()Ljava/lang/String;
  #44 = Class              #57            // java/io/PrintStream
  #45 = NameAndType        #58:#59        // println:(Ljava/lang/String;)V
  #46 = Utf8               jvm/ConstantPoolTest
  #47 = Utf8               java/lang/Object
  #48 = Utf8               java/util/Comparator
  #49 = Utf8               java/lang/System
  #50 = Utf8               out
  #51 = Utf8               Ljava/io/PrintStream;
  #52 = Utf8               append
  #53 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #54 = Utf8               (I)Ljava/lang/StringBuilder;
  #55 = Utf8               toString
  #56 = Utf8               ()Ljava/lang/String;
  #57 = Utf8               java/io/PrintStream
  #58 = Utf8               println
  #59 = Utf8               (Ljava/lang/String;)V

3.为什么需要常量池

java中的字节码需要数据支持,通常这种数据很大以至于不能直接存到字节码里,那么可以换另一种方式,将它们存到常量池里。通过在字节码里包含指向常量池的引用,来查找具体的地址。另外,由于字节码中不需要存储过大的数据(如上述类所继承的Object类、实现的Comparator接口),可以有效地减少字节码文件的大小。

二、什么是运行时常量池

运行时常量池是方法区的一部分。字节码文件中的常量池经过类加载子系统被加载到方法区后形成的结构就称为运行时常量池。

在这里插入图片描述运行时常量池中包含多种不同的常量,包含编译器就已经明确的数值字面量,也包含到运行期解析后才能获得的方法或者字段引用。相较于常量池,它具有动态性。如"CSDN".intern(),如果在常量池中没有"CSDN"时,就会在运行时常量池中创建。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值