Java 7 字符串 - 子字符串复杂性
在 Java 6 之前,我们在 上有一个恒定时间子字符串。在Java 7中,为什么他们决定使用复制数组 - 并降级到线性时间复杂性 - 而类似的东西正是为此而生的?String
char
StringBuilder
在 Java 6 之前,我们在 上有一个恒定时间子字符串。在Java 7中,为什么他们决定使用复制数组 - 并降级到线性时间复杂性 - 而类似的东西正是为此而生的?String
char
StringBuilder
为什么他们决定在Oracle错误#4513622中讨论:(str)保留字段的子字符串会阻止对象的GC:
如示例中所示调用 String.substring 时,不会为存储分配新的字符数组。它使用原始字符串的字符数组。因此,支持原始字符串的字符数组不能被GC'd,直到子字符串的引用也可以是GC'd。这是一项有意的优化,以防止在常见方案中使用子字符串时分配过多。不幸的是,有问题的代码会遇到原始数组的开销很明显的情况。很难针对两种边缘情况进行优化。任何空间/大小权衡的优化通常都很复杂,并且通常可能是特定于平台的。
还有这个注释,指出曾经的优化已经变成了根据测试的悲观化:
很长一段时间以来,准备和刨削一直在进行,以从java.lang.String中删除偏移和计数字段。这两个字段使多个 String 实例能够共享相同的支持字符缓冲区。共享字符缓冲区是旧基准测试的重要优化,但对于当前的实际代码和基准测试,实际上最好不要共享支持缓冲区。共享 char 数组支持缓冲区只有在大量使用 String.substring 时才“获胜”。负面影响的情况可能包括解析器和编译器,但目前的测试表明,总的来说,这种变化是有益的。
如果您有一个短寿命的大父字符串的长寿命小子字符串,则在小子字符串移出范围之前,支持父字符串的大 char[] 将不符合垃圾回收的条件。这意味着子字符串可以占用比人们预期的更多的内存。
Java 6方式唯一一次表现得更好是当有人从一个大的父字符串中获取一个大的子字符串时,这是一个非常罕见的情况。
显然,他们认为这种变化的微小性能成本被旧方法引起的隐藏内存问题所抵消。决定因素是问题被隐藏了,而不是有解决方法。