3

如果我们看一下String#substring方法实现:

new String(offset + beginIndex, endIndex - beginIndex, value);

我们看到使用相同的原始内容(参数char [] value)创建了一个新 String。

因此解决方法是使用 new String(toto.substring(...))删除对原始 char[] 值的引用并使其符合 GC 条件(如果不存在更多引用)。

我想知道是否有特殊原因可以解释此实现。为什么该方法不为自己创建新的较短的字符串,以及为什么她保留完整的原始值?

new String(...)另一个相关的问题是:在处理子字符串时我们应该总是使用吗?

4

3 回答 3

2

因为String不可变

另见

于 2012-06-20T09:14:06.637 回答
2

我想知道是否有特殊原因可以解释此实现。为什么该方法不为自己创建新的较短的字符串,以及为什么她保留完整的原始值?

因为在大多数substring()用例中,以这种方式工作会更快。至少,这就是 Sun / Oracle 的经验测量所显示的。通过这样做,实现避免了分配支持数组并将字符复制到数组。

如果您必须复制字符串以避免内存泄漏问题,这只是非优化。在绝大多数情况下,子串在比较短的时间内就变成了垃圾,并且没有长期的内存泄漏。


假设,Java 设计者可以提供两个版本的substring,一个与当前行为相同,另一个创建一个带有自己的支持数组的 String 。但这会鼓励开发人员浪费脑力循环考虑使用哪个版本。然后是建立在子字符串上的实用方法的问题......例如Pattern/Matcher类。所以我认为他们没有这样做是件好事。

于 2012-06-20T09:20:09.400 回答
1

这种实现的原因是效率。通过指向与char[]原始字符串相同,不需要复制任何数据。

不过,这确实有一个缺点,正如您已经暗示过自己的那样。如果原始字符串很长,你只想得到它的一小部分,之后不再需要原始字符串,那么完整的原始数组仍然被引用,不能被垃圾收集。您已经知道如何避免这种情况 - 做new String(original.substring(...))

new String(...)我们应该在处理子字符串时总是使用吗?

不,并非总是如此。只有当您知道它可能会导致问题时。在许多情况下,参考原始char[]数据而不是复制数据更有效。

于 2012-06-20T09:22:17.417 回答