Java字符串常量池的理解

176 阅读1分钟

前置知识

在Java7之前,JVM内存模型中有永久代(Premanent Generation的概念,方法区以此实现,字符串常量池就放在其中 image-1655272381582

在Java7之后字符串常量池等被移至堆区内,在Java8永久代被正式移除,取而代之的是元空间(MetaSpace)

例子

    String s = new String("1");
    s.intern();
    String s2 = "1";
    System.out.println(s == s2);

    String s3 = new String("1") + new String("1");
    s3.intern();
    String s4 = "11";
    System.out.println(s3 == s4);

jdk6结果为false false jdk7结果为 false true new String("1")执行后,生成了两个对象,一个是string对象,还有一个值为“1”的字符串常量 s.intern()因为常量存在,所以不会再次将"1"放入常量池 s2 = "1" 会直接获得字符串常量的引用,而s为字符串对象的实例引用,所以结果为false

new String("1") + new String("1");执行后同样也是两个对象和一个常量"1",最终合并为一个string对象,值为“11”,但是并没用放入字符串常量池 s3.intern()将“11"放入常量池,jdk6和jdk7的区别就在此

  • jdk6中使用Intern()是若常量池中不存在此字符串,就将此字符串复制一份放入永久代的常量池中然后返回引用,引用存在于方法区,而s3的实例存在于堆区,所以对比地址肯定是不一样的
  • jdk7的常量池在堆区,在s3.intern()之后,常量池查无此字符串,不同于jdk6复制一份放入premGen中,而是先在堆区内寻找实例,将实例引用放入常量池,所以s4="11"获取的就是s3的实例引用

image-1655274505518

image-1655274549022