在JDK6 和JDK 7 里面substring(int beginIndex, int endIndex)的方法是不同的。
知道这种区别会帮助你更好用它们。为了简单期间,下面用substring() 来表示 substring(int beginIndex,Int endIndex) 方法。
substring方法作用
substring(int beginIndex,int endIndex)方法返回一个从beginIndex开始,到endIndex-1结束的字符串。
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
/* 输出: */
bc
调用的时候发生了什么
你也许知道,因为x是不可变的,所以当x被赋值为x.substring(1,3)的时候,它指向了一个全新的字符串,如下图所示:
但是,这个图片没有正确的说明在堆里面发生的事情。在JDK6和JDK7 中调用substring()真正发生了什么。
在JDK6中substring()
String 可以被标示成字符数组。在JDK6中,String 类包含三个属性: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);
}
在JDK6中引起的问题
如果你有个非常长的字符串,但是你每次想通过用substring()来取其中一小部分。这将会产生一个性能问题,你仅仅需要一小部分,但是你保留了整个。在JDK6中,通过下面的方法,将使它指向一个真正的子串。
推荐可以用如下方法:
x = new String(x.substring(x, y)); 或 x = x.substring(x, y) + ""
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);
}
注意:因为有拷贝另外一个,听说JDK7的效率比JDK6的substring方法效率低些,不过因内存占用过大影响效率问题。
`