substring(int beginIndex, int endIndex) 方法在JDK 7中实现方式是不同于JDK6的,了解这两版本的区别可以帮助你更好的使用它们。简单起见,以下 用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是final不可变的,所以当x被重新赋值为x.substring(1,3)时,它应该指向一个全新的字符串,就像下面图片显示的那样:
但是这张图并不完全正确,它并没有说明内存堆中真正发生了什么。那么substring()方法的到底是怎样工作的呢?在JDK6和JDK7中又有什么区别呢?
3. JDK 6 中的substring()
实际上String类的原理是将字符串存储在一个字符数组中的,在JDK6中,类String包括3个属性域: char value[], int offset, int count,分别用来存储实际的字符数组、数组的第一个索引、字符的个数。
当substring()方法被调用时,一个新的字符串被创建,但是这个字符串的字符数组value仍然指向了原来那个数组的内存堆!惟一不同的是两个字符串的offset和count属性值不同,如下图:
下面是简化后的String类源码:
//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);
}
可以看到value并没有变!
4. JDK6 substring()方法引出的一个问题
如果有一个很长很长的字符串,你每次只需要截取其中很短的一小段,但是如果你用substring()的话实际会得到很长很长的字符串的引用,所以当使用的时候必然导致性能降低! 解决方法可以你下面那样让x指向一个新子串:
x = x.substring(x, y) + ""
5. JDK7中的substring()
这个问题在JDK7中被改进了,创建了一个新的字符数组:
String类在JDK7中的源码:
//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);
}
可以看到,在构造函数中,创建了一个全新的字符数组value,并且String类中不再使用offset和count做为属性了。
原文地址:http://www.programcreek.com/2013/09/the-substring-method-in-jdk-6-and-jdk-7/
原文标题:The substring() Method in JDK 6 and JDK 7