String在JDK6 JDK7 JDK8之中的变迁

为了您更好的理解本篇文章,请先查阅
https://blog.csdn.net/define_us/article/details/78252783 中的JVM分代管理策略一节。

JDK6

JDK的String常量池存在于Perm区,和JAVA Heap区是完全不同的两个区域。通过字符串常量生成的String对象存在在永久代上,而通过new产生的对象,分配在JAVA HEAP上。intern会查看是否有String常量池的值等于当前字符串,如果没有,把在常量池新建该值的字符串对象。然后把常量池中的字符串对象返回。

    public static void main(String[] args) {
        //指向常量池中的同一个字符串对象
        String s5 = "111";
        String s6 = "111";
        System.out.println(s5 == s6);//true

        //s8是intern后返回的常量池中的字符串对象
        String s7 = "111";
        String s8 = new String("111").intern();
        System.out.println(s7 == s8);//true

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

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

    }
  • JDK6有一个硬伤,就是subString的内存泄漏问题
    如下代码:
String str = "abcdefghijklmnopqrst";
String sub = str.substring(1, 3) + "";
str = null;

运行结束后str内部的char数组不会被回收,因为substring是通过调整边界实现的。在str被置为null后,sub内部仍然引用者char数组。

    public String substring(int var1, int var2) {
        return var1 == 0 && var2 == this.count ? 
        this : new String(this.offset + var1, var2 - var1, this.value);//这里复用了当前字符串的value数组。
    }

    String(int var1, int var2, char[] var3) {
        this.value = var3;
        this.offset = var1;
        this.count = var2;
    }    

采用如下方式就可以解决该问题。

String str = "abcdefghijklmnopqrst";
String sub = str.substring(1, 3) + "";
str = null;

JDK8

在JDK8中运行上述代码,结果变成了

true
true
false
true

猜你喜欢

转载自blog.csdn.net/define_us/article/details/82223291