简易Java(07):substring()
方法在JDK6和JDK7中的异同
看到
substring()
,D瓜哥就想起来去年面试的惨痛精力。连续两次被问到substring()
会造成什么问题;第一次被问到时,确实不知道会造成什么问题,面试结束后就查了查资料。但是,没有认真看。没想到接下来的面试又问到,由于没有看,还是没回答上来,结果面试就惨遭失败!没想到,这次又遇到了
substring()
。所以,这篇文章D瓜哥必须好好翻译!
substring()
会造成什么问题,请看参考资料。另外,需要提前说明一点,本节内容是针对Oracle JDK来说明的,其他JDK的实现也许可能不同。请读者自己查看相关文档以及源代码。
substring(int beginIndex, int endIndex)
方法,在JDK6和JDK7中的实现是不一样的。了解实现的不同之处,可以帮助我们更好地使用这个方法。为了简单起见,下文中用substring()
指代substring(int beginIndex, int endIndex)
。
1、substring()
的作用是啥?
substring(int beginIndex, int endIndex)
方法将返还字符串,这个字符串是原字符串从beginIndex
开始,到endIndex-1
的子串。
/** * Coder: D瓜哥,http://www.diguage.com/ */ String x = "abcd"; x = x.substring(1, 3); System.out.println(x);
输出为:
bc
2、当substring()
被调用时,背后发生了什么?
我们在上一篇文章“图解Java字符串的不可变性 ”讲到,字符串x
是不可变的。所以,当x
被重新赋值为x.substring(1, 3)
时,它指向了一个全新的字符串。如下图所示:
尽管,这个图并不能完全正确地说明堆栈中的确实发生的变化。不过,却可以帮助我们说明,当substring()
被调用时,在JDK6和JDK7下究竟有什么不同。
3、JDK6中的substring()
字符串是通过字符数组的方式来实现的。在JDK6中,String
类包含三个属性:char value[]
、int offset
、int count
,它们分别用于存储真实的字符数组、数组的开始下标以及字符串中的字符数量。
当调用substring()
时,它将创建一个新的字符串对象,但是字符串的值还是指向堆栈中同一个数组。两个字符串对象不同的只是它们的字符数量以及开始下标。如下图所示:
/** * Coder: D瓜哥,http://www.diguage.com/ */ // 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) { // 边界检查 return new String(offset + beginIndex, endIndex - beginIndex, value); }
4、JDK6的substring()
导致的问题
如果你有一个非常长的字符串,但是你每次调用substring()
,只需要其中的很小一部分。那么,这将导致一个性能问题,尽管你仅仅需要很小的一部分,但是,却保存了所有的字符。对于JDK6,使用下面的代码,可以解决这个问题,可以使得对象x
确实指向一个真正的子字符串:
x = x.substring(m, n) + "";
5、JDK7中的substring()
上面提到的问题,在JDK7中已经改正。在JDK7中,substring()
方法确实会在堆栈中创建一个新的数组。如下图所示:
D瓜哥注:
这个图片有部分地方是错误的:
int count
和int offset
已经不是Oracle JDK7中String
的属性。大家可以从String
的源代码中确认!
/** * Coder: D瓜哥,http://www.diguage.com/ */ // JDK 7 String(char value[], int offset, int count) { // 边界检查 this.value = Arrays.copyOfRange(value, offset, offset+count); } public String substring(int beginIndex, int endIndex) { // 边界检查 int subLen = endIndex - beginIndex; return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
《Simple Java》是一本讲解Java面试题的书。讲解也有不少独特之处,为了面试,《简易Java》走起!
参考资料
原文链接:substring()方法在JDK6和JDK7中的异同">https://wordpress.diguage.com/archives/93.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。