substring(int beginIndex, int endIndex)在JDK6与JDK7中的实现方式不一样,理解他们的差异有助于更好的使用它们。为了简单起见,下面所说的substring()指的就是substring(int beginIndex, int endIndex)方法。
1.substring()是做什么的?
substring(int beginIndex ,int endIndex)方法返回一个子字符串,返回的是从原字符串的beginIndex到endIndex-1之间的内容。
1 2 3 | String x = "abcdef" ; x = x.substring( 1 , 3 ); System.out.println(x); |
输出:
1 | "bc" |
2.当substring()被调用的时候,内部发生什么事?
你或许会认为由于x是不可变的对象,当x被x.substring(1,3)返回的结果赋值后,它将指向一个全新的字符串如下图:
然而,这个图并不完全正确,或者说并没有完全表示出java 堆中真正发生的事情。那么当调用substring()的时候到底发生的了什么事呢?JDK 6与JDK7的substring方法实现有什么不一样呢?
3.JDK6中的substring()
java中字符串是通过字符数组来支持实现的,在JDK6中,String类包含3个域,char[] value、int offset、int count。分别用于存储真实的字符数组、数组的偏移量,以及String所包含的字符的个数。
当substring()方法被调用的时候,它会创建一个新的字符串对象,但是这个字符串的值在java 堆中仍然指向的是同一个数组,这两个字符串的不同在于他们的count和offset的值。
下面是jdk6中的原代码,是简化后只包含用来说明这个问题的关键代码:
1 2 3 4 5 6 7 8 9 10 11 | //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()将会导致的问题
如果你有一个非常长的字符串,但是你仅仅只需要这个字符串的一小部分,这就会导致性能问题(译注:可能会造成内存泄露,这个bug很早以前就有提及),因为你需要的只是很小的部分,而这个子字符串却要包含整个字符数组,在jdk6中解决办法就是使用下面的方法,它会指向一个真正的子字符串。
1 | x = x.substring(x, y) + "" |
5.JDK7中的substring()
在JDK7中有所改进,substring()方法在堆中真正的创建了一个新的数组,当原字符数组没有被引用后就被GC回收了.因此避免了上述问题.
1 2 3 4 5 6 7 8 9 10 11 | //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); } |
=======================================================================
/** * 如何重复一个字符串 */ String str = "abcd"; String repeated = StringUtils.repeat(str, 3); System.out.println("repeated : " + repeated); /** * 如何计算一个字符串某个字符出现的次数 */ int n = StringUtils.countMatches("hanchaohan@126.com", "a"); System.out.println("我的邮箱中出现a的次数:" + n);