在AbstractStringBuilder的JDK源代码中,append(int)
方法的实现方式不会分配不必要的内存(使用char[]
直接写入内部Integer.getChars
)。
但insert
的实现使用String.valueOf
返回一个新字符串,然后将该数据复制到数组中。创建垃圾字符串。
不是StringBuilder
的一个要点来缓解串联字符串的垃圾影响。实现insert
的无垃圾实现似乎微不足道。那为什么不呢?
Oracle JDK和OpenJDK似乎都是这种情况。它甚至在javadoc中提到:
整体效果就像第二个参数通过方法String.valueOf(int)转换为字符串一样,然后该字符串的字符在指定的偏移处插入到该字符序列中。
答案 0 :(得分:2)
如果您将insert(int,int)
与其他insert
方法进行比较,您会发现实施方法是保持简单,通过让单个insert(String)
方法完成所有操作来减少代码重复实际工作。
这是一种合理的软件开发方法,首先创建一个处理所有案例的直接通用实现,然后使用实际应用程序进行分析。找到创建专门的,可能不那么简单的优化版本的地方的场景有一个好处。似乎没有搜索到找到可以使用相同优化实现的其他地方。考虑到前面的测量结果显然没有将insert(int,int)
显示为一个重要的热点,这并不会造成伤害。
要评估这种情况,重要的是要了解临时对象的数量不会使重复String.concat
代价高昂。过度创建临时物体可能会给火焰增加燃料,因此如果有一个简单的选择,它仍然值得避免。但重复String.concat
调用的问题是每个临时字符串实例的创建意味着复制构成字符串内容的整个字符数据。您的字符串构建越多concat
调用,您就越接近二次时间复杂度。
StringBuilder
通过使用可变缓冲区解决了这个问题。当容量耗尽时,它仍然被复制,但通过使用因子来确定新容量,总体时间复杂度保持线性。 insert
的实施并没有改变这一基本原则。临时String
实例仅导致复制右侧,因此它只引入一个常数因子2,而不是改变时间复杂度。
但是不要忘记insert
原则上会复制缓冲区的后续字符数据。如果您在缓冲区的开头重复插入,则无论底层实现的优化程度如何,您都将转向二次时间复杂度。因此,如果你过度这样做,那么两倍的因素将变得可以忽略不计。