众所周知,在您生成相同源字符串的许多子字符串的情况下,Java会优化子字符串操作。 它通过使用(value, offset, count)
存储信息的方式来做到这一点。 请参阅以下示例:
在上图中,您会看到字符串“ Hello”和“ World!”。 源自“ Hello World!” 以及它们在堆中的表示方式:有一个包含“ Hello World!”的字符数组。 和两个引用。 在某些情况下,例如对于标记化源文件的编译器,这种存储方法是有利的。 在其他情况下,这可能会导致您遇到OutOfMemorError(如果您常规地读取长字符串并且仅保留其中的一小部分,但是上述机制会阻止GC收集原始的String缓冲区)。 有些甚至称它为错误 。 我不会走那么远,但这肯定是一个泄漏的抽象,因为您被迫执行以下操作以确保创建了副本: new String(str.substring(5, 6))
。
这一切都在2012年5月或Java 7u6中进行了更改。 钟摆向后摆动,现在默认情况下会制作完整副本。 这对您意味着什么?
- 在大多数情况下,这只是Java琐事中的一个不错的片段
- 如果您正在编写解析器等,则不能再依赖String提供的隐式缓存了。 您将需要基于缓冲和CharSequence的自定义实现来实现类似的机制
- 如果您正在执行
new String(str.substring)
来强制字符缓冲区的副本,则可以在更新到最新的Java 7时立即停止(并且由于Java 6处于EOLd状态 ,因此您需要尽快这样做) 说 )。
值得庆幸的是,Java的开发是一个开放的过程,并且这些信息在每个人的指尖!
与字符串相关的另外两个引用(因为我们没有说Java中的指针):
- 如果您要一遍又一遍地存储相同的字符串(例如,您正在从套接字解析消息),则应阅读String.intern()的替代方法 (并考虑阅读第二版的《有效》,第50章)。 Java:避免使用其他类型更合适的字符串)
- 查看(并在使用它们之前做基准测试!)诸如UseCompressedStrings( 似乎已被删除 ),UseStringCache和StringCache之类的选项
希望我没有对您造成太大伤害,您发现这很有用! 直到下一次
–阿提拉·巴拉兹(Attila Balazs)
中继:这篇文章是Java Advent Calendar的一部分,并根据Creative Commons 3.0 Attribution许可获得许可。 如果您喜欢它,请通过共享,发推,FB,G +等来传播信息! 想为博客写文章吗? 我们正在寻找能够填补所有24个职位的贡献者,并希望能为您贡献力量! 联系Attila Balazs贡献力量!
参考:在Java Advent Calendar博客上,我们的JCG合作伙伴 Attila-Mihaly Balazs 对Java 7中的String.substring进行了更改 。
翻译自: https://www.javacodegeeks.com/2012/12/changes-to-string-substring-in-java-7.html