字符串常量池和String::intern()的讨论

Posted doubest

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串常量池和String::intern()的讨论相关的知识,希望对你有一定的参考价值。

2.3 字符串常量池和String::intern()的讨论

2.3.1 Java堆中的内存泄漏与内存溢出

1、内存泄漏指垃圾收集器无法回收,导致该部分内存没办法得到利用,泄漏了,占用内存。

2、内存溢出就是指Java堆中创建的对象所占用的内存大小,已经超过了Java堆可扩展内存的最大范围,导致内存溢出。

2.3.2 字符串常量池和String::intern()的讨论

1、String::intern()是一个本地方法(由Java栈管理),当一个字符串对象调用str.intern()方法时会发生以下调用过程:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

2、我们考虑以下代码:

public static void main(String[] args) {
    // 之所以用append是因为,一打出“计算机软件”就会创建字符串对象并放到常量池,探究意义不大
    String str1 = new StringBuilder("计算机").append("软件").toString();
    System.out.println(str1.intern() == str1);

    String str2 = new StringBuilder("ja").append("va").toString();
    System.out.println(str2.intern() == str2);
}

(1)在JDK6环境下运行,结果为两个false。,在JDK 6中,intern()方法会把首次遇到的字符串实例复制到永久代的字符串常量池中存储返回的也是永久代里面这个字符串实例的引用。意思就是说StringBuilder.toString()的字符串在Java堆中,而intern()出来的字符串在字符串常量池中,不可能会有同样的地址。

(2)在JDK7中,此时原本存放在永久代的字符串常量池被移至Java堆之中,intern()方法实现就不需要再拷贝字符串的实例到永久代了,既然字符串常量池已经移到Java堆中,那只需要在常量池里记录一下首次出现的实例的地址即可,intern()出来的字符串和Java堆中的字符串地址一模一样。

那么,按照上述分析,JDK7环境下应该会返回两个true啰?答案是一个true,一个false。原因如下:

对于“计算机软件”这5个字,并没有出现在常量池中,因此intern()时,常量池中没有引用,就会在常量池中创建一个引用,并指向Java堆中的“计算机软件”字符串对象。因此第一个是true。

对于“java”这4个字,它在这个程序运行之前就已经在常量池中了,因此intern()返回的和刚创建的"java"字符串对象地址不一样。

以上是关于字符串常量池和String::intern()的讨论的主要内容,如果未能解决你的问题,请参考以下文章

String.intern()字符串常量池

常量池之字符串常量池String.intern()

java String.intern 和 字符串常量池

再议String-字符串常量池与String.intern()

String.intern() 学习

几张图轻松理解String.intern()