JDK6和JDK7中的substring()方法

substring(int beginIndex, int endIndex)在JDK6与JDK7中的实现方式不一样,理解他们的差异有助于更好的使用它们。为了简单起见,下面所说的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是不可变的对象,当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中的原代码,是简化后只包含用来说明这个问题的关键代码:

//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中解决办法就是使用下面的方法,它会指向一个真正的子字符串。

x = x.substring(x, y) + ""

5.JDK7中的substring()

在JDK7中有所改进,substring()方法在堆中真正的创建了一个新的数组,当原字符数组没有被引用后就被GC回收了.因此避免了上述问题.

//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);
}

 

原文链接: programcreek 翻译: ImportNew.com - 刘志军
译文链接: http://www.importnew.com/7418.html
[ 转载请保留原文出处、译者和译文链接。]

关于作者: 刘志军

程序员,关注 Java、Python、云计算,移动互联网。(新浪微博:@_Zhijun

查看刘志军的更多文章 >>



相关文章

发表评论

Comment form

(*) 表示必填项

6 条评论

  1. wungcc 说道:

    我查了查jdk1.7.0没有修改

    Thumb up 0 Thumb down 0

  2. zmy5353 说道:

    string的字符數組是不是存在string常量池中?常量池不是不進行gc嗎,這裡有些不懂,幫忙解釋下,多謝

    Thumb up 1 Thumb down 0

    • qarkly 说道:

      String str = “1234″;
      String str_1 = new String(“1234″);
      像str 放在String常量池中,而str_1 新申请对象,放在堆中。
      所以 使用 str==str_1判断一定是false,而String str_2 = “1234″;
      str==str_2 判断是true

      Thumb up 3 Thumb down 0

  3. Viva 说道:

    我刚去Oralce JDK 6u45中查了下,substring的实现方式仍然没有改变。可能PO主需要再Double Confirm一下然后改一下“译注”

    最新的Oracle JDK 7u51里确实改过了。

    Thumb up 1 Thumb down 0

  4. neal 说道:

    哈 这个new的问题,的确有用,以后编码的时候,new对象的时候要注意一下这个, 以前可能在某些代码里面就是直接引用,不过字符串大小都不大就是了

    Thumb up 0 Thumb down 0

跳到底部
返回顶部