这是本人第一次翻译及时文档,如有差池,还请多多体谅,本人还是觉得,如果读者英文功底,还可以的话,建议看原文:http://www.programcreek.com/2013/09/the-substring-method-in-jdk-6-and-jdk-7/
为简单起见,列举如下例子来说明substring(int beginIndex,int endIndex)方法。
1,substring()方法具体是做什么的?
substring(int beginIndex , int endIndex)方法返回一个从beginIdex开始到endIndex-1的新串。
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
输出结果:
bc
2,substring()方法什么时候被调用?
我们知道对于String的长度是不变的,当x调用substring(1,3)方法后,返回的结果会指向一个全新的字符串,如下:
然而,上图并不完全正确反应出substring()方法在堆中发生的情况,在JDK 6 和JDK 7中是有区别的。
3,JDK 6中的substring()方法
由于字符串支持字符数组,在JDK 6 中,有这样一个构造器。
String
public String(char[] value,
int offset,
int count)分配一个新的 String,它包含取自字符数组参数一个子数组的字符。offset 参数是子数组第一个字符的索引,count 参数指定子数组的长度。该子数组的内容已被复制;后续对字符数组的修改不会影响新创建的字符串。
参数:
value - 作为字符源的数组。
offset - 初始偏移量。
count - 长度。
当substring()方法被调用后,会创建一个新的字符串,但是这个新的字符串仍旧指向原来字符串在堆中的地址,这两个字符串的区别就是他们的长度和初始偏移量。
如下的一段伪代码用来解释这个问题:
//JDK 6
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);
}
4,JDK 6中由substring()引出的弊端
如果你有一个很长的字符串,但是你仅仅只需要其中的一小部分,当每次使用substring()截取子串时,会有此出现性能问题。因为你只需要一小部分,但是你需要将原来的字符串都保存下来。但是JDK 6 提供了如下的解决方案,用来指向你真正需要的字符串:
x = x.substring(x, y) + ""
5,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);