自动字符串常量池化

5

在源代码中的com.sun.org.apache.xerces.internal.impl.XMLScanner 的183行和186行

183    protected final static String fVersionSymbol = "version".intern();

186    protected final static String fEncodingSymbol = "encoding".intern();

为什么“version”和“encoding”是字符串字面量,并且会自动成为串汇,但仍然使用intern()显式的进行串汇?


2
+1 好问题!效果是一样的,但是生成的字节码有所不同。我猜除非我们直接向作者询问,否则我们永远不会知道答案。我认为这是过早的优化。 - OscarRyz
2个回答

6
我已经追踪到更改,它位于Apache Xerces SVN存储库中的318617修订版(这是最初开发此XML解析器的项目,如软件包名称所示)。
提交消息的相关部分为:
尝试改进符号表的使用。每次重置解析器时,将许多预定义字符串添加到符号表中。对于小型文档,这将是一个显着的成本。现在,由于我们对符号表中的字符串调用了String#intern,因此对于那些预定义的符号,使用String#intern就足够了。这只需要执行一次。
正如您指出的那样,.intern()在符合JVM实现的情况下不应该是必要的(并且不应该有任何可见效果)。
我的猜测是
要么作者不知道字符串字面值将始终被内部化的事实,
要么这是一项有意识的决定,以防止JVM实现的错误行为。
然而,在第二种情况下,我希望在注释或注释消息中能够看到一些说明。

.intern()的一个副作用是,初始化程序不再是常量表达式,并且其他引用它们的类将无法内联这些字段。这将确保加载类XMLScanner并读取其字段。然而,我认为这在这里并不相关。


1
在提交信息中:...每次重置解析器时都会向符号表添加许多预定义字符串...现在,由于我们为符号表中的字符串调用了String#intern...对于那些预定义的符号,使用String#intern就足够了。这只需要执行一次即可。很明显,作者不希望再次将预定义的字符串符号从代码中添加到符号表中,每次重置解析器都要这样做。因此,作者很可能不知道字符串文字会自动进行内部化。 - a Learner

4

我不认为有任何好的理由来支持你提出的原因:文字常量都会自动地被作为 String类所规定的 进行整合:

所有的文字常量和以字符串值定义的常量表达式都会进行整合。关于字符串文字的定义可参见 《Java™ 语言规范》 3.10.5 章节。


1
这是一种糟糕编程的示例吗? - a Learner
2
@aLearner:我想是吧。可能我不会那么强烈地表达这个观点,但至少如果有一个充分的理由(虽然我怀疑),我期望会有一段注释来解释这是为什么。 - T.J. Crowder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接