在JDK7之前,String类中的substring方法新建的对象与原对象指向同一个数组,具体来说:
/**JDK6*/
public final class String {
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
/** 在下面substring中创建新的String对象时使用了改构造函数 */
public String(int offset, int count, char value[]) {
/**第一处*/
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
/**第二处*/
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
}
第二处在判断beginIndex和endIndex满足条件后新建出一个String对象,如上图所示。在new的过程中使用了String(int offset, int count, char value[])构造方法,该方法只是将成员变量重新赋值,因此新旧两个String对象都指向同一个数组。
从JDK7开始,substring方法中新建的对象与原String对象指向不同的数组,具体如下:
/**JDK7*/
public final class String {
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
/**第一处*/
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
/**第二处*/
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
}
/**Arrays.copyOfRange*/
public static char[] copyOfRange(char[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
char[] copy = new char[newLength];
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength));
return copy;
}
与JDK6相比,第二处更换了构造方法,该构造方法通过this.value = Arrays.copyOfRange(value, offset, offset+count)来对成员变量赋值,查看Arrays的copyOfRange静态方法,发现该方法新建了一个copy对象并返回,也就是说,通过该构造方法,新旧的String对象不再指向同一处,如上图所示。
参考链接
https://blog.csdn.net/du_an_a_nuo/article/details/50853046
https://blog.csdn.net/u010293702/article/details/46560289
https://www.cnblogs.com/treeAndCloud/p/7249266.html