コンパイル時の複雑さと実行時の複雑さを混同しています。
クラスがロードされると、はい、各リテラルが既に存在するかどうかを確認するために検索を行います (ただし、提案の代わりに O(1) ルックアップにハッシュマップを使用すると思います)。
コードが実行されると、メモリ内の文字列への参照が保持されるため、非リテラル以外の追加コストはありません。
はい、リテラルはインターンされます。文字列の Javadoc によると、
最初は空である文字列のプールは、クラス String によってプライベートに維持されます。
String を呼び出しintern()
て、このプールに追加できます。一意のプールから戻ることが保証されているため、論理的には if a.equals(b)
thenに従います。a.intern() == b.intern()
.intern()
例:
class InternTest {
// assuming InternTest is the only class, internPool.size = 0
String x = "ABC"; // interned at class load, internPool.size = 1
String y = "DEF"; // interned at class load, internPool.size = 2
String z = "ABC"; // interned at class load, but match found - size = 2 still
void foo() {
// random int is just a mechanism to get something that I know won't
// be interned at loadtime - could have loaded from file or database too
int i = (new java.util.Random()).nextInt(1000) + 100;
int j = i;
String s = String.valueOf(i); // not yet interned, size = 2 still
String t = String.valueOf(j); // not yet interned, size = 2 still
String sIntern = s.intern(); // manually interned, size = 3 now
String tIntern = t.intern(); // manually interned, match found, size = 3 still
System.out.println("equals: " + (s.equals(t))); // should be true
System.out.println("== raw: " + (s == t)); // should be false, different variables
System.out.println("== int: " + (sIntern == tIntern)); // should be true, from unique pool
System.out.println("x and z: " + (x == z)); // should be true, interned at class load
}
public static void main(String[] args) {
(new InternTest()).foo();
}
}
実行時の結果:
C:\Documents and Settings\glowcoder\My Documents>java InternTest
equals: true
== raw: false
== int: true
x and z: true
この仮定は決して真実ではないことを指摘しておきます。Java 言語自体には、私たちの言語が日の目を見るString
前に抑留される多くの言語があります。String
ただし、すべてがシーケンシャルにロードされると仮定し、インターンされている Strings のデルタのみを考慮し、既存のインターンとの衝突がないと仮定すると (インターンがうるさく、ドラマに満ちていることは誰もが知っていますよね?スニッカー)、数字は実際に文字列プールのサイズのデルタ。