JVM - 常量池理解

1. 字符串常量池

  • Heap中,在编译阶段就把所有的字符串文字放进去
  • 是一个StringTable类,它是一个哈希表,里面存的是字面值(也就是我们常说的用双引号括起来的)的引用(而不是字面值实例本身)

字符串常量池的位置

  • 在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中
  • 在JDK7.0版本及之后,字符串常量池被移到了堆中

1.1 String str = new String(“abc”);

规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。

  1. 先定义一个名为str的对String类的对象引用变量放入栈中。
  2. 然后在中(不是常量池)创建一个指定的对象,并让str引用指向该对象。
  3. 常量池中查找是否存在内容为"abc"字符串对象;如果不存在,则在常量池中创建内容为"abc"的字符串对象,并将堆中的对象与之联系起来;如果存在,则将new出来的字符串对象与字符串常量池中的对象联系起来(即让那个特殊的成员变量value的指针指向它)

延伸问题:String s = new String(“abc”);产生几个对象?答:一个或两个,如果常量池中原来没有”abc”,就是两个。

1.2 String str = “abc”;

  1. 先定义一个名为str的对String类的对象引用变量放入栈中。
  2. 常量池(Heap中的)中查找是否存在内容为"abc"字符串对象。
  3. 如果不存在则在常量池中创建"abc",并让str引用该对象;如果存在则直接让str引用该对象。

String的 intern() 方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;

总结:

对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中;如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

2. class文件常量池(静态常量池)

class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译器生成的各种字面量和符号引用。字面量就是我们所说的常量概念,如字符串、被声明为final的常量值等。符号引用是一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可(它与直接引用区分一下,直接引用一般是指向方法区的本地指针,相对偏移量或是一个能间接定位到目标的句柄)。一般包括下面三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

它是Class文件中的内容,还不是运行时的内容,可以理解为Class文件中的字节码指令。

3. 运行时常量池

是方法区的一部分(运行时常量是相对于常量来说的)。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用。当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值