String常量池

一、第一步

  当前所使用的jdk版本是1.8
  首先我们需要注意的是有运行期与编译期,而运行期还得区分运行时的类加载过程与实际执行某个代码片段。
  当代码为:

String a=“abc”

时,由于字符串字面量会在编译期就被编译到.class二进制文件中,当虚拟机加载该class文件的时候,这种字符串字面量会被JVM初始化成一个String对象,存储在字符串常量池中,在jdk1.8里字符串常量池是在堆里的,而Constant Table\String table则在Native Memory,Constant Table\String table存储的是字符串常量池里的String对象引用,所以"abc"String对象不会被gc回收,即使变量都没引用它,为什么呢?因为Constant Table\String table里还储存着其String对象引用。请看下图。
在这里插入图片描述

二、第二步

而当代码为

String a= new String("abc");

  摘取R神的话与我使用的代码相结合:在符合规范的JVM实现中,在运行时类加载的过程中创建并驻留一个String实例作为常量来对应"abc"字面量;具体是在类加载的resolve阶段进行的。这个常量是全局共享的,只在先前尚未有内容相同的字符串驻留过的前提下才需要创建新的String实例。

  所以当代码为以下时

① String a = new StringBuilder().append("abc").toString();//        String a= new String("abc"); 
③System.out.println(a.intern() == a);//false

  不管是①还是②,他们在③得到的结果都是false,为什么呢?我们来分析以下:
  当代码为①③的时候,代码运行到new StringBuilder时会在堆中创建一个StringBuilder的实例对象,而"abc"字面量会在堆内存(jdk1.7以后版本字符串常量池中的对象被迁移到堆内存中)里创建"abc"字符串对象实例,该过程是在类被加载的时候做到的,在类加载时遇到字面量的时候会在interned string pool/StringTable查看有没有其引用,若没有,则会在堆中创建"abc"字符串对象实例,然后将其引用记录在interned string pool/StringTable中,当调用到StringBuilder的toString方法,其底层其实就是new String(value,0,count)【这里在后面我会重点讲一下】,所以这时候就会在堆内存中创建一个String的实例对象,并赋予变量a,如上图所示,这时候a.intern拿到的其实是图中的①,而a本身还是②,所以为false。
  当代码为②③时,其实和①③是一样的,因为StringBuilder的toString()方法里用到的也是 new String,所以a.intern() == a 的结果也为false。请看下图。
在这里插入图片描述

三、最后一步

  当代码为

String s1 = new StringBuilder().append("ja").append("va1").toString();       
System.out.println(s1.intern() == s1);//true
 

  当类加载的时候会先判断interned string pool/StringTable内是否已存在该字面量的引用,若没有则实例化字面量,所以图中的①和②就此而来,当代码执行到.toString()的时候,会new 一个值为java1的String实例对象,那么就有了图中的③了,这个时候你是不是会问那为什么java1不会再类加载时就实例化呢?因为当类加载时字面量只有ja和va1,而java1是在代码运行时(类已经加载好了)才组合而成的,所以不会在加载时就实例化,只有组合成后才能确定该值为何值,所以这时候才通过new关键字创建了值为java1的String实例对象,所以当s1.intern()的时候,会去interned string pool/StringTable查看有没有当前实例对象的值的引用,有的话就返回其中记录的引用,没有的话就将当前实例对象的引用记录到其中,而结果发现是没有的就将当前的引用记录到interned string pool/StringTable中,图中的④就由此而来。
  那么结果s1.intern() == s1都指向同一个对象,肯定是true的了。请看下图。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值