(说明,该文章翻译自The substring() Method in JDK 6 and JDK 7)
在JDK 6 and JDK 7中的substring(int beginIndex, int endIndex) 方法是不同的。了解这个不同能够帮助你更好的使用它们。为了简单起见,我将使用substring()
来表示substring(int beginIndex, int endIndex)
这个方法
1.substring()
做了什么
substring(int beginIndex, int endIndex) 方法返回了一个以beginIndex开始以endIndex-1结尾的字符串。
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
输出
`bc`
2.当substring()被调用的时候会发生什么
你应该知道因为x
是不可变的,所以当x被分配调用结果x.substring(1,3)
,它会执行一个全新的数组就像下面所示一样:
但是这个图片并不是完全准确的表示出实际在堆中发生的事情。当这个方法被调用的时候在JDK6和JDK7中是不一样的。
3.在JDK6中的substring()
String底层是有一个char类型的数组来实现的。在JDK6中,String类含有3个属性: char value[], int offset, int count。他们用来存储真的字符数组,数组的第一个索引值,字符串中字符的数量。
当一个substring()方法被调用的时候,它创建了一个字符串,但是在堆内存中这个字符串的值仍然执行相同的数组。这两个字符串之间的区别就是他们的count和offset。
下面的简单代码表示了这个关键的不同之处
//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.在JDK6中substring()方法引起的问题
如果你使用一个非常长的字符串,但是你在每次使用substring()方法时只是需要其中很小的一部分。这将会引起性能上的问题,因为你只是需要一个小部分但是你需要维持整个数组。对于JDK6来说,可以使使用下面的解决方案,因为它将使它指向一个真正的子串:
x = x.substring(x, y) + ""
5.在JDK7中的substring()方法
这个在JDK7中得到了改善。在JDK7中,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);
}