2009-12-02 68 views
34

我看到这样大量的遗留代码使用实习生())当对字符串字面

class A { 
    public static final String CONSTANT = "value".intern(); 
    ... 
} 

我看不出有任何理由实习生(如在Javadoc一个可以读取: “所有文字字符串和字符串值常量表达式都被禁用。”有没有这个意图,也许在过去的语言版本?

+7

除了pjp之外,没有其他人在回答之前实际阅读过这个问题吗? – Adamski 2009-12-02 15:34:25

+0

[是否所有编译时常量内联?](http://stackoverflow.com/questions/377819/are-all-compile-time-constants-inlined) – 2012-07-09 16:44:53

回答

65

这是一种技术,以确保CONSTANT实际上不是一个常数。

当Java编译器看到对最终静态基元或String的引用时,它会将该常量的实际值插入使用它的类中。如果您然后在定义的类中更改常量值,但不重新编译使用的类,它将继续使用旧值。

通过在“常量”字符串上调用intern(),它不再被编译器视为静态常量,因此using类在每次使用时都会实际访问定义类的成员。


JLS引文:编译时间常数的

+4

现在,这就是我所说的诡计 – pjp 2009-12-02 15:49:29

+1

我刚刚通过实验证实了这一点,但是有没有JLS引用? – 2009-12-02 15:52:40

+0

这类似于http://stackoverflow.com/questions/377819/are-all-compile-time-constants-inlined – pjp 2009-12-02 15:54:20

16

intern()与常量字符串字面量相结合是浪费时间,因为字面量已按照的The Java® Language Specification部分的规定进行实施。

从Java SE 8版报价:

而且,文字始终是一个字符串是指String类的同一个实例。这是因为字符串文字 - 或者更一般地说是常量表达式(§15.28)值的字符串 - 被“实施”,以便使用方法String.intern共享唯一实例。

我猜编码器不理解这个事实。

编辑:

由于kdgregory指出有这个常量是如何被内联的影响。

1 - https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

+3

JLS谈论结果,但它不明确无论这种折叠是在编译时发生的,还是只是在运行时编译时折叠与连接与然后实例之间不应有明显差异。字节代码检查将回答两个字符串串联文字是否在类文件中成为一个。 – seh 2009-12-02 16:04:39

5

前段时间我实习生()ed所有o f来自类文件的字符串(用于类文件解析器)。 Intern()ing使程序使用较少的内存(不会像其他人指出的那样),但它确实减慢了程序的速度(我认为花费4秒钟的时间来解析所有rt.jar,超过8秒)。在当时考虑它(我认为是JDK 1.4)intern()代码非常难看,而且可能需要更慢。

如果我想考虑在代码中调用intern(),我会首先在没有intern()的情况下对其进行配置文件,然后使用intern()对内存和速度进行配置并查看哪一个更糟糕。

+2

哇...和准确的信息的倒票是什么?提供的信息是否错误? – TofuBeer 2009-12-03 01:31:51

+0

确实pjp在这个问题上相当慷慨downvotes – 2009-12-03 11:29:02

+2

我不关心倒票...只是他们的原因:-) – TofuBeer 2009-12-03 15:15:48

0

我已经用intern()来“锁定”。例如,假设我有一个“贸易记录”的“存储库”。当我编辑和更新交易时,我想锁定交易;我可能会锁定在tradeId.intern()上,这样我就不用担心浮动交易的克隆了。我不确定是否每个人都喜欢这种用法。

这假定id字段是不太可能意外地与另一个域对象的ID字段碰撞 - 一个tradeId不会发生与ACCOUNT_NUMBER例如,碰撞,其中一个也可能会做

synchronized(account.getAccountNumber().intern()) {...} 

请参阅example

+0

是不是scala的符号基本上在做String.intern()? – 2012-01-21 01:51:21