Java的String内存池的实现是否遵循flyweight模式?
为什么我有这个疑问,我看到实习生没有涉及外在国家。在GoF我读到内在和外在状态之间应该有一个正确的平衡。但在实习生中,一切都是固有的。
或者我们应该说没有关于属性的严格规则,只是共享对象以减少内存就足以称之为flyweight。
请帮助我理解。
答案 0 :(得分:3)
无论是否实习,Java String都会通过char[]
和类似的方法调用在字符串和从字符串派生的字符串之间共享substring
来使用flyweight模式。但是,这有另一个方面:如果你接受一个巨大字符串的一个小子串,那么巨大的char[]
就没有资格进行垃圾收集。
注意:从OpenJDK版本1.7.0_06开始,上述内容已经过时:代码已更改,因此实例之间不再共享char[]
。 substring()
创建一个新数组。
答案 1 :(得分:3)
是String.intern()
实现遵循flyweight模式。
正如javadoc所说
返回字符串对象的规范表示。一池水 最初为空的字符串由String类私有维护。
当调用实习方法时,如果池已包含 字符串等于此字符串对象由equals(Object)确定 方法,然后返回池中的字符串。否则,这个 String对象被添加到池中以及对此String的引用 返回对象。
对于任何两个字符串s和t,s.intern()== t.intern() 当且仅当s.equals(t)为真时才为真。
所有文字字符串和字符串值常量表达式都是 实习。字符串文字在Java语言的§3.10.5中定义 说明书
内化字符串驻留在“Perm Gen”空间和.intern()
返回的字符串对象上,您可以使用运算符==
,因为.intern()
始终返回相同值的相同对象。
然后记住.intern()
方法不会产生泄漏,因为今天的JVM可以对池进行垃圾处理。
尝试阅读此article。
答案 2 :(得分:3)
您已正确识别Interning和Flyweight都基于相同的想法:缓存和共享共同状态。
使用Flyweight,在没有外部状态存储的极端情况下,只有指向内部状态的指针仍然存在。那么外在状态甚至不需要成为一个对象,指针本身也可以是外在状态。当Flyweight成为实习生时。
是否实习"真的"是或不是一种Flyweight只是对定义的争论。最重要的是理解如何将一个人视为另一个人的特殊实例,这样你就会很好。
答案 3 :(得分:0)
就像其他人所说,String.intern()就是缓存。它返回对池中已存储的字符串文字的引用。通过这种方式,它与flyweight模式类似,因为它使用现有对象,从而降低了内存消耗并提高了性能(尽管实习生在字符串池中也有自己的查找性能开销)。因此,这两者似乎相似,但实际上并非如此。
答案 4 :(得分:0)
否,共享对象以减少内存不足以称其为“轻量级”。换句话说,缓存不会自动成为“举重”模式。
我认为公平地说,flyweight是一种特殊的缓存形式,即部分缓存;但请注意,GoF手册在flyweight章节的任何地方都没有使用“ cache”或“ caching”一词(尽管上一章和后续章节分别使用了术语“ facade”和“ proxy”)。
此线程中的一些评论值得重复,因为它们简洁地回答了整个问题。
如果您的对象没有外部上下文,那么您只是在缓存。 Flyweight模式甚至有用的全部原因 定义是人们经常忘记他们至少可以缓存一部分 与上下文无关的对象并共享它。
-CS
Flyweight是关于共享对象内部的。实习只是缓存整个对象。
-马尔科·托波尔尼克
但是让我们将String实习与GoF定义的标准进行比较(第197页)。
当以下所有 all 为真时,应用Flyweight模式:
- 应用程序使用大量对象。
- 由于对象数量巨大,因此存储成本很高。
- 大多数对象状态可以是外部的。
- 一旦移除外部状态,许多对象组可能会被相对较少的共享对象所代替。
- 该应用程序不依赖于对象标识。由于可以共享轻量级对象,因此对于概念上不同的对象,身份测试将返回true。
==
比较Java中的字符串的任何人都知道不依赖于对象身份,因此该标准可以通过。4/5合格标准相当不错吧?难道不是说interning / caching和flyweight都一样吗?否:相似!=相同。 GoF引用中对单词 all 的强调是他们的,而不是我的。自然,人们强烈希望使用GoF模式名称标记尽可能多的实现,因为这样做会使这些实现具有合法性。 (最糟糕的情况是工厂模式,您可以轻松地找到各种可以想象的创建代码标签;但是我离题了。)如果这些模式不符合其已发布的定义,它们就会重叠并失去意义,从而破坏了大部分他们的目的(常用词汇)。
最后,让我们分析一下“举重”一章的第一句话:GoF定义为“举重”模式的 Intent 。
使用共享有效地支持大量细粒度对象。
我认为没有外部状态的对象不是细粒度的,而是相反的。因此建议使用以下 Intent 进行缓存:使用缓存可以有效地支持大量的粗粒度对象。
很明显,String插入/缓存和Flyweight模式之间有相似之处;但是它们不一样。
答案 5 :(得分:-1)
Flyweight是关于共享对象immutables内部。实习只是缓存整个对象。