Java subString 方法

本文探讨了JDK7中String类substring方法的实现变化。从早期版本的O(1)时间复杂度到JDK7后的O(n),虽然算法效率有所降低,但通过分配新空间存储子字符串的方式有效避免了内存泄漏风险。文章通过具体示例说明了这种改动如何解决了潜在的垃圾回收问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jdk7之前substring实现方法

-截取一部分jdk的关键实现

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

jdk7版本之后的实现

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

原因分析

从算法的时间复杂度方面来比较,第一个版本的复杂度为o(1), 第二个版本的复杂度为o(n),但是为什么jdk7之后要选用后面这个实现,只要是因为第一个实现会影响到垃圾回收,第一个版本调用substring不会分配新空间用于存储字符,使用的是原始字符串的字符数组,这样到时原始字符串即使没有了引用了空间也不会被回收,考虑一个特殊场景,当你有一个很长的字符串,但是每次只使用其中一个很小的子串,例如,一下这段程序很出现OOM:

public class TestGC {
    private String largeString = new String(new byte[100000]);
    private String smallString = "foo";

    String getString() {
        // if caller stores this substring, this object will not be gc'ed
        return this.largeString.substring(0,2);
//        return new String(this.largeString.substring(0,2)); // no error here!
//        return smallString; // no error here!
    }

    public static void main(String[] args) {
        java.util.ArrayList list = new java.util.ArrayList();
        for (int i = 0; i < 1000000; i++) {
            TestGC gc = new TestGC();
            list.add(gc.getString());
        }
    }
}

更详细的可以参考http://bugs.java.com/view_bug.do?bug_id=4513622
以及https://stackoverflow.com/questions/16123446/java-7-string-substring-complexity

### Java 中 `substring` 方法的使用说明 #### 单参数版本:`public String substring(int beginIndex)` 此方法用于返回一个新的字符串,该字符串是从当前字符串中截取的一部分,起始索引为指定的 `beginIndex` 参数,直到字符串结束为止。如果输入的索引超出范围,则会抛出 `StringIndexOutOfBoundsException` 异常[^1]。 示例代码如下: ```java public class SubstringExample { public static void main(String[] args) { String str = "HelloWorld"; System.out.println(str.substring(5)); // 输出 "World" } } ``` --- #### 双参数版本:`public String substring(int beginIndex, int endIndex)` 此方法同样返回一个新的字符串,但它允许指定两个索引位置——起始索引 (`beginIndex`) 和终止索引 (`endIndex`)。新字符串的内容是从 `beginIndex` 开始到 `endIndex - 1` 结束的部分。需要注意的是,`endIndex` 所指向的位置不会被包含在结果字符串中。如果任意一个索引超出了有效范围或者 `beginIndex > endIndex`,则会抛出 `StringIndexOutOfBoundsException` 异常[^3]。 下面是一个双参数版本的例子: ```java public class SubstringDoubleParamExample { public static void main(String[] args) { String str = "HelloWorld"; System.out.println(str.substring(0, 5)); // 输出 "Hello" } } ``` --- #### 注意事项 - 如果调用者传入负数作为索引值,将会引发异常。 - 当前实现下,对于某些 JDK 版本(如早期版本),`substring()` 返回的结果可能共享原始字符串的底层字符数组;但在较新的 JDK 实现中,这种行为已被更改以减少内存占用并提高安全性[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值