String类中substring方法的内部实现以及内存泄漏详解

在JDK7之前,String类中的substring方法新建的对象与原对象指向同一个数组,具体来说:

/**JDK6*/
public final class String {
	 /** The value is used for character storage. */
    private final char value[];
 
    /** The offset is the first index of the storage that is used. */
    private final int offset;
 
    /** The count is the number of characters in the String. */
    private final int count;

    /** 在下面substring中创建新的String对象时使用了改构造函数 */
    public String(int offset, int count, char value[]) {
    /**第一处*/
        this.value = value;
        this.offset = offset;
        this.count = count;
    }

    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);
    }
}
内存分析
内存分析1

第二处在判断beginIndex和endIndex满足条件后新建出一个String对象,如上图所示。在new的过程中使用了String(int offset, int count, char value[])构造方法,该方法只是将成员变量重新赋值,因此新旧两个String对象都指向同一个数组。

从JDK7开始,substring方法中新建的对象与原String对象指向不同的数组,具体如下:

/**JDK7*/
public final class String {
	 /** The value is used for character storage. */
    private final char value[];
 
    /** The offset is the first index of the storage that is used. */
    private final int offset;
 
    /** The count is the number of characters in the String. */
    private final int count;
    
    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
    /**第一处*/
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }
    public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
    /**第二处*/
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
}
    /**Arrays.copyOfRange*/
    public static char[] copyOfRange(char[] original, int from, int to) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        char[] copy = new char[newLength];
        System.arraycopy(original, from, copy, 0,
                         Math.min(original.length - from, newLength));
        return copy;
    }
内存分析2

与JDK6相比,第二处更换了构造方法,该构造方法通过this.value = Arrays.copyOfRange(value, offset, offset+count)来对成员变量赋值,查看Arrays的copyOfRange静态方法,发现该方法新建了一个copy对象并返回,也就是说,通过该构造方法,新旧的String对象不再指向同一处,如上图所示。

 

如有任何错误,请评论区或者邮箱(kaaryachen@163.com)告知,谢谢

参考链接

https://blog.csdn.net/du_an_a_nuo/article/details/50853046

https://blog.csdn.net/u010293702/article/details/46560289

https://www.cnblogs.com/treeAndCloud/p/7249266.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值