当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

深入string的substring方法

发表于: 2014-04-14   作者:bijian1013   来源:转载   浏览次数:
摘要: 1.应用举例         substring方法,例如s="abcdef"  s.substring(2,5)结果为cde,长度为endindex-beginindex 2.实现原理 /** * Returns a new string that is a substring of th

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

        通过源代码可以发现

        a).string内部通过char[]数组实现

        b).substring方法返回了新的string对象,但是string对象却指向原来得char数组,如果原来的string很大,即使原来的string释放,内存空间也无法回收

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

        d).默认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];
}

        e).内存泄露测试

package com.bijian.study.string;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class StringTest {

	public static void main(String[] args) throws UnsupportedEncodingException {
		
		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[]都那么大。
原因解释:
        a.程序从每个请求中得到一个String大对象,该对象内部char[]的长度达数百K。
        b.程序对String大对象做split,将split得到的String小对象放到HashMap中,用作缓存。
        c.Sun JDK6对String.split方法做了优化,split出来的Stirng对象直接使用原String对象的char[]
        d.HashMap中的每个String对象其实都指向了一个巨大的char[]
        e.HashMap的上限是万级的,因此被缓存的Sting对象的总大小=万*百K=G级
        f.G级的内存被缓存占用了,大量的内存被浪费,造成内存泄露的迹象
解决方案:
        split是要用的,但是我们不要把split出来的String对象直接放到HashMap中,而是调用一下String的拷贝构造函数String(String original),这个构造函数是安全的,源代码如下:

/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param  original
*         A {@code String}
*/
public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
    // The array representing the String is bigger than the new
    // String itself.  Perhaps this constructor is being called
    // in order to trim the baggage, so make a copy of the array.
    int off = original.offset;
    v = Arrays.copyOfRange(originalValue, off, off+size);
} else {
    // The array representing the String is the same
    // size as the String, so no point in making a copy.
    v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
} 

文章来源: http://blog.csdn.net/hanruikai/article/details/7479775

深入string的substring方法

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
本文将对String.substring方法可能产生内存泄漏的问题进行分析,并给出相应的优化方法。 String.subs
本文将对String.substring方法可能产生内存泄漏的问题进行分析,并给出相应的优化方法。 String.sub
1、subString()方法的作用   subString(int beginIndex, int endIndex)方法的返回的是以beginInde
substring() 用法:<字符串对象>.substring(<始>[, <终>]); 返回原字符串的子字
在jdk1.6中,substring的使用要格外引起注意,首先我们来看看substring是如何实现的: 通过源代码我
Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它
一、从根本上认识java.lang.String类和String池 首先,我建议先看看String类的源码实现,这是从本质
Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它
Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它
substring(int beginIndex, int endIndex) 方法在 JDK 6 和 JDK 7 中是不一样的. 了解他们之间的异
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号