原创

JDK 1.6和JDK 1.7中substring的原理及区别

String的subString方法作用: 截取字符串并返回其[beginIndex,endIndex-1]范围内的内容。

分析

我们知道,因为字符串的不可变性,当使用 x.substring(1,3) 对x赋值的时候,它会指向一个全新的字符串。
但是在jdk6 和 jdk7中调用substring时处理逻辑并不一样。

JDK 6中的substring

String是通过字符数组实现的。在jdk 6 中,String类包含三个成员变量:char value[], int offset,int count。他们分别用来存储真正的字符数组,数组的第一个位置索引以及字符串中包含的字符个数。

当调用substring方法的时候,会创建一个新的string对象,但是这个string的值仍然指向堆中的同一个字符数组。这两个对象中只有count和offset 的值是不同的。

源码代码

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

public String substring(int beginIndex, int endIndex) {
    //check boundary
    return  new String(offset + beginIndex, endIndex - beginIndex, value);
}

导致的问题

如果你有一个很长很长的字符串,但是当你使用substring进行切割的时候你只需要很短的一段。

这可能导致性能问题,因为你需要的只是一小段字符序列,但是你却引用了整个字符串(因为这个非常长的字符数组一直在被引用,所以无法被回收,就可能导致内存泄露)。

在JDK 6中,一般用以下方式来解决该问题,原理其实就是生成一个新的字符串并引用他。
x = x.substring(x, y) + ""

JDK 7 中的substring

在jdk 7 中,substring方法会在堆内存中创建一个新的数组。

源码代码

//JDK 7
public String(char value[], int offset, int count) {
    //check boundary
    this.value = Arrays.copyOfRange(value, offset, offset + count);
}

public String substring(int beginIndex, int endIndex) {
    //check boundary
    int subLen = endIndex - beginIndex;
    return new String(value, beginIndex, subLen);
}

JDK 7中的subString方法,其使用new String创建了一个新字符串,避免对老字符串的引用。从而解决了内存泄露问题。

~ end

正文到此结束
广告是为了更好的提供数据服务
本文目录