substring()字节字符截取两种方式及内存泄漏问题

substring()或者substr()是大部分主流语言所支持的,同时对字符串的操作是编程中最频繁的操作,当然对截取字符串也是最常用操作之一。所以今天就讨论一下subtring()。

以JAVA举例,在JAVA中我们看看系统提供的substring()有什么问题?

我们首先看看JDK中substring()的源码:

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

这段代码主要的这行:new String(offset + beginIndex, endIndex - beginIndex, value)

我们在进这个String构造方法,看看它做了什么?

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

我们发现惊奇的发现JDK源码中很少有对一个函数进行单行注释,这里居然出现了,肯定是作者尤其强调的,用博主“拙劣”的英文水平帮着翻译下它的意思:私有构造器共享着value数组为了去提高效率。接下来我们看看这个String构造函数,我们发现它在截取字符串的时候创造一个String对象但是引用了原来的char value[],利用偏移量的方式达到一个截取的效果,我们并不需要原来的字符串了,但JVM通过扫描发现原来的String的对象还有引用指向它,所以不能回收。这就造成了内存泄漏。

PS:JDK7版本已解决上诉问题,感兴趣的朋友可以去看源码。

所以当对内存要求高的时候,或者需要提高软件寿命,我们需要对它进行处理,博主在这里提供两种方法:

方式一:既然截取后的字符串引用指向原来的对象,我们当然可以让这个子字符串自己独占一个对象,原来的字符串就可以被回收了。

比如String newStr = s.substring(1,3); 改成String newStr = new String(s.substring(1,3));

方式二:我们大可自己写一个substring()函数

代码清单:

public class MySubString {
	
	public static void main(String[] args) {

		String s = "人在江湖,记录那些有趣的事";
		System.out.println(substring(s, 2, 4));
		System.out.println(substring(s, 2));

	}

	public static String substring(String s, int begin, int end) {
		if(null == s || "".equals(s))
			return null;
		if (begin < 0 || end > s.length() || end - begin < 0)
			return null;
		char[] cs = s.toCharArray();
		char[] new_cs = new char[end - begin];//待返回的字符数组
		int index = 0;
		for (int i = begin; i < end; i++) {
			new_cs[index++] = cs[i];
		}
		return new String(new_cs);
	}

	public static String substring(String s, int begin) {
		return substring(s, begin,s.length());
	}

	
}


有的语言比如像PHP,它的截取字符串函数substr()函数是按字节截取的,我们知道在不同编码下,一个汉字所占 字节数是不同的,所以用它截取中文可能会产生乱码,所以这种情况下用字符截取方便的多(PHP中iconv_substr()是按字符截取的),但也有很多情况需要用到字节截取,但我们知道JAVA的字符串是按字符截取的,它并没有字节截取的函数,所以我们有时得自己写按字节截取的substring()

代码清单:

public class MySubString {
	
	public static void main(String[] args) {

		String s = "人在江湖,记录那些有趣的事";
		System.out.println(subStringByByte(s, 2, 4));
		System.out.println(subStringByByte(s, 2));

	}


	public static String subStringByByte(String s, int begin, int end) {
		
		if(null == s || "".equals(s))
			return null;
		if (begin < 0 || end > s.getBytes().length || end - begin < 0)
			return null;
		byte[] bs = s.getBytes();
		byte[] new_bs = new byte[end-begin];
		int index = 0;
		for(int i = begin; i < end; i++){
			new_bs[index++] = bs[i];
		}
		return new String(new_bs);

	}
	public static String subStringByByte(String s, int begin) {
		return subStringByByte(s, begin, s.getBytes().length);
	}

	
}


==================================================================================================

  作者:nash_  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/nash_/article/details/8282525

===================================================================================================

展开阅读全文

没有更多推荐了,返回首页