2009-12-02 71 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