jvm 字符串常量池String table

前言

我们都知道java有很多中常量池,如字节码常量池Constant pool运行时常量池字符串常量池String tableInteger等基本数据类型常量池,各自之间很容易混淆,今天我们就来探索一下字符串常量池。

基本介绍

字符串常量池String table是用于存放String字面量的,用于使字符串可以进行复用,节省内存空间,其本质是一个hashSet,即内部是一个hash表。
在jdk1.7以前,字符串常量池是放在方法区中的,里面存放的都是字符串实例,即字面量值,所以一个字符串在jvm中会存在多个实例,比如"abc".intern(),就会将"abc"的实例复制一份到方法区的字符串常量池中。
在jdk1.7及以后,方法区中的字符串常量池就移动到了堆heap中,这样字符常量池中存的就是字符串实例的引用,可以通过在jvm启动参数中设置-XX:StringTableSize=2000来设置字符串常量池的大小,最低不能低于1009。

字符串常量池中存储内容

  1. 首先当然是String s = "abc"这种使用双引号申明的字符串字面量会被放入,String s = “abc” + "def"这种使用字面量进行拼接的字符串,会在编译时优化为"abcdef"放入字节码常量池,从而进入字符串常量池,而用变量进行拼接的则会使用StringBuilder进行拼接,不会进入字符串常量池:
public class StringTest3 {
    public static void main(String[] args) {
        String a = "aa";
        String b = "bb";
        String c = a + b;
        String d = "aabb";
        String e = "aa" + "bb";
        System.out.println(c == d); //false
        System.out.println(d == e); //true
    }
}
  1. 字节码常量池constant pool中的内容,我们都知道字节码常量池是类编译后存放在.class字节码文件中的,其中有类名,方法名,类和方法的修饰符,字符串字面量,符号引用(该类中引用的类的全限定类名),在该字节码文件被类加载器加载到jvm中,字节码常量池中的内容在堆heap中创建对应的String对象实例,引用存放到运行时常量池,然后引用再放到字符串常量池中(这是我的猜想,目前还没有在书上或者权威的地方得到验证),以下是我用代码做的验证:
public class StringTest3 {
    public static void main(String[] args) {
       String e = new String("ma") + new String("in"); //"main"是方法修名, 在编译时就存在class文件的常量池中
        e.intern();
        System.out.println(e == "main"); //false
        String f = new String("ma") + new String("in11");
        f.intern();
        System.out.println(f == "main11"); //ture
    }
}

你们觉得会输出true,true,其实是false,true, 因为"main"是方法名,会被放在字节码常量池,类加载后就到了字符串常量池,所以e.intern()就不会生效:
在这里插入图片描述

  1. String.intern()会把在字符串常量池中不存在的字符串放入其中,这体现了字符串常量池的动态性。

String s = new String(“abc”)与String s = “abc”

这又扯到了一个高频面试题,String s = new String(“abc”)会创建几个对象,如果在new String()之前,有String s = "abc"语句声明了字符串,则创建一个对象;如果"abc"第一次出现,没有在字符串常量池就创建两个对象,new String(“abc”)的过程其实可以分为两步:

  1. String s1 = “abc”;
  2. String s = new String(s1);
    第一步先在堆中new一个值为"abc"的String对象,然后将其引用放到字符串常量池中,第二步就将字符串常量池中的引用赋值给new String(),相当于s底层的char []指向的地方和s1指向的地方是一样(但是并不能代表s1 == s),具体位置如下:
    jvm
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值