在JDK 8中,StringBuffer
类有toStringCache
,而StringBuilder
没有。{/ p>
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
但为什么?
我能想到的一个可能原因是StringBuffer已经同步,因此可以更轻松地实现缓存。
或者也许历史上StringBuffer是以这种方式实现的,因此旧代码在很大程度上依赖于此功能?
鉴于具有转义分析和偏向锁定的现代JVM,差异是否相关?
答案 0 :(得分:5)
考虑历史背景可能会有所帮助。 Java {5}引入了StringBuilder
,因为已经认识到StringBuffer
不适合其实际用例。
新引入的StringBuilder
是针对在纯粹的本地环境中构建,使用和立即删除的主要用例而设计的。因此,它没有提供任何同步,并且它没有考虑优化罕见的toString()
方法被多次调用而没有中间更改(这在现实生活中何时发生?),事实上,在不牺牲无线程同步的性能优势的情况下提供缓存功能,介于“硬”到“不可能”之间。
虽然StringBuilder
被记录为不是线程安全的,所以你知道在同时调用方法时会发生不一致的事情,类String
通过不变性保证线程安全,因此,它不允许StringBuilder
缺少同步可能导致已构造的字符串不一致,并且根本不在String
和StringBuilder
之间共享数组,这是最安全的解决方案。
那么,为什么这种优化在那里,如果它在现实生活中几乎没有任何好处?好吧,因为它存在很长一段时间,很可能甚至从Java 1.0开始,并且不值得改变类StringBuffer
中的任何内容。它的存在可能没有任何真正的优势,但也没有删除它,这将需要新的测试等等,并可能成为某些应用程序的space bar overheating feature ......
你可能会注意到,在Java 1.x中,很多设计决策在今天看起来很奇怪。在基础课中过度使用synchronized
就是其中之一,这几乎没有帮助优化另一个。当时,即使是不可变性的含义也没有得到很好的理解,这就是为什么我们有String.valueOf(char[])
和String.copyValueOf(char[])
这样的冗余方法,以及使用new String(char[])
的机会......
答案 1 :(得分:3)
我认为你的第一个猜测是高度准确的,因为StringBuilder
不是线程安全的,并且一个实例可以在多个线程之间共享,实现这样的缓存需要额外的同步,这将失去{的目的{1}}首先。
至于为什么需要这个,它归结为使用的StringBuilder
构造函数;如果new String(...)
使用构造函数StringBuffer
,则评论说:
打包私有构造函数,它为速度共享值数组。