string深入之subString,stringsubstring
分享于 点击 3989 次 点评:165
string深入之subString,stringsubstring
1、应用举例
subString方法,例如s="abcdef" s.subString(2,5)结果为cde,长度为endindex-beginindex
2、实现原理
/**
* Returns a new string that is a substring of this string. The
* substring begins at the specified <code>beginIndex</code> and
* extends to the character at index <code>endIndex - 1</code>.
* Thus the length of the substring is <code>endIndex-beginIndex</code>.
* <p>
* Examples:
* <blockquote><pre>
* "hamburger".substring(4, 8) returns "urge"
* "smiles".substring(1, 5) returns "mile"
* </pre></blockquote>
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
* <code>beginIndex</code> is negative, or
* <code>endIndex</code> is larger than the length of
* this <code>String</code> object, or
* <code>beginIndex</code> is larger than
* <code>endIndex</code>.
*/
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);
}
通过源代码可以发现
11、string内部通过char[]数组实现
12、subString方法返回了新的string对象,但是string对象却指向原来得char数组,如果原来的string很大,即使原来的string释放,内存空间也无法回收
13、offset值默认为0,第一个参数为偏移,第二个为长度,第三个为char数组
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
14、默认string构造方法如下:
/**
* Initializes a newly created {@code String} object so that it represents
* an empty character sequence. Note that use of this constructor is
* unnecessary since Strings are immutable.
*/
public String() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}
15、内存泄露测试代码
package com.string;
import java.util.ArrayList;
import java.util.List;
public class TestSubstringLeak {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String aa=new String(new char[100000]);
List<String> list=new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
//虽然截取的字符串占据空间很小,但是由于aa巨大的数组空间被共享,没有释放,所以内存溢出
// list.add(aa.substring(2, 3));
list.add(new String(aa.substring(2,3)));//加一层构造方法后,构造方法内部进行了数组的拷贝,原有的巨大数组空间被回收,不会内存溢出
}
}
}
为了避免内存拷贝、加快速度,Sun JDK直接复用了原String对象的char[],偏移量和长度来标识不同的字符串内容。也就是说,subString出的来String小对象仍然会指向原String大对象的char[],split也是同样的情况 。这就解释了,为什么HashMap中String对象的char[]都那么大。
原因解释
其实上一节已经分析出了原因,这一节再整理一下:
解决方案
原因找到了,解决方案也就有了。split是要用的,但是我们不要把split出来的String对象直接放到HashMap中,而是调用一下String的拷贝构造函数String(String original),这个构造函数是安全的,具体可以看代码:
相关文章
- 暂无相关文章
用户点评