jdk7之前substring实现方法
-截取一部分jdk的关键实现
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);
}
jdk7版本之后的实现
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);
}
原因分析
从算法的时间复杂度方面来比较,第一个版本的复杂度为o(1), 第二个版本的复杂度为o(n),但是为什么jdk7之后要选用后面这个实现,只要是因为第一个实现会影响到垃圾回收,第一个版本调用substring不会分配新空间用于存储字符,使用的是原始字符串的字符数组,这样到时原始字符串即使没有了引用了空间也不会被回收,考虑一个特殊场景,当你有一个很长的字符串,但是每次只使用其中一个很小的子串,例如,一下这段程序很出现OOM:
public class TestGC {
private String largeString = new String(new byte[100000]);
private String smallString = "foo";
String getString() {
// if caller stores this substring, this object will not be gc'ed
return this.largeString.substring(0,2);
// return new String(this.largeString.substring(0,2)); // no error here!
// return smallString; // no error here!
}
public static void main(String[] args) {
java.util.ArrayList list = new java.util.ArrayList();
for (int i = 0; i < 1000000; i++) {
TestGC gc = new TestGC();
list.add(gc.getString());
}
}
}
更详细的可以参考http://bugs.java.com/view_bug.do?bug_id=4513622
以及https://stackoverflow.com/questions/16123446/java-7-string-substring-complexity