私はこのようなレガシーコードをたくさん見ます:
class A {
public static final String CONSTANT = "value".intern();
...
}
Javadocのように、intern()の理由はわかりません。「すべてのリテラル文字列と文字列値の定数式はインターンされています。」おそらく過去の言語の改訂で、これの意図はありますか?
私はこのようなレガシーコードをたくさん見ます:
class A {
public static final String CONSTANT = "value".intern();
...
}
Javadocのように、intern()の理由はわかりません。「すべてのリテラル文字列と文字列値の定数式はインターンされています。」おそらく過去の言語の改訂で、これの意図はありますか?
これは、CONSTANT
が実際には定数ではないことを確認する手法です。
Java コンパイラは、最終的な静的プリミティブまたは文字列への参照を検出すると、その定数の実際の値を、それを使用するクラスに挿入します。その後、定義クラスの定数値を変更しても、使用するクラスを再コンパイルしないと、古い値が引き続き使用されます。
「定数」文字列で intern() を呼び出すと、コンパイラによって静的定数と見なされなくなるため、使用するクラスは、使用するたびに定義クラスのメンバーに実際にアクセスします。
JLS の引用:
コンパイル時定数の定義: http://docs.oracle.com/javase/specs/jls/se6/html/expressions.html#5313
コンパイル時の定数への変更の影響 (ページの約半分): http://docs.oracle.com/javase/specs/jls/se6/html/binaryComp.html#45139
セクション3.10.5intern()
で指定されているように、リテラルは既にインターンされているため、定数文字列リテラルで を使用するのは時間の無駄です。Java® 言語仕様の文字列リテラル。
Java SE 8 Edition からの引用:
さらに、文字列リテラルは常に String クラスの同じインスタンスを参照します。これは、文字列リテラル (より一般的には、定数式の値である文字列 (§15.28)) が、メソッド String.intern を使用して一意のインスタンスを共有するために「インターン」されているためです。
コーダーはこの事実を理解していなかったと思います。
編集:
kdgregoryが指摘したように、この定数がどのようにインライン化されるかについて影響があります。
1 - https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5
少し前に、クラスファイルからのすべての文字列をインターン()しました(クラスファイルパーサー用)。Intern()ing により、プログラムのメモリ使用量が減りました (他の人が指摘したように、この場合はそうではありません) が、プログラムの速度が大幅に低下しました (rt.jar のすべてを解析するのに 4 秒かかったと思います。その変更により、 8 秒以上)。当時(JDK 1.4だったと思います)調べてみると、 intern() コードはかなり醜くて遅く、おそらくそうする必要があります。
コードで intern() を呼び出すことを検討する場合、最初に intern() なしでプロファイリングし、次にメモリと速度の両方について intern() でプロファイリングし、どちらが変更に対して「悪い」かを確認します。
「ロック」に intern() を使用しました。たとえば、「取引記録」の「リポジトリ」があるとします。取引を編集および更新している間、取引をロックしたい。代わりに、tradeId.intern() をロックして、トレードのクローンが浮かんでいることを心配する必要がないようにすることもできます。誰もがこの使い方を気に入っているかどうかはわかりません。
これは、id フィールドが別のドメイン オブジェクトの id フィールドと誤って衝突する可能性が低いことを前提としています - たとえば、tradeId が account_number と衝突することはありません。
synchronized(account.getAccountNumber().intern()) {...}
例を見る