字串池和堆儲存
像許多 Java 物件一樣,所有 String
例項都是在堆上建立的,甚至是文字。當 JVM 發現在堆中沒有等效引用的 String
文字時,JVM 在堆上建立相應的 String
例項,並且它還儲存對 String 池中新建立的 String
例項的引用。對同一 String
文字的任何其他引用都將替換為堆中先前建立的 String
例項。
我們來看下面的例子:
class Strings
{
public static void main (String[] args)
{
String a = "alpha";
String b = "alpha";
String c = new String("alpha");
//All three strings are equivalent
System.out.println(a.equals(b) && b.equals(c));
//Although only a and b reference the same heap object
System.out.println(a == b);
System.out.println(a != c);
System.out.println(b != c);
}
}
以上的輸出是:
true
true
true
true
當我們使用雙引號建立一個 String 時,它首先在 String 池中查詢具有相同值的 String,如果發現它只返回引用,否則它在池中建立一個新 String,然後返回引用。
但是,使用 new 運算子,我們強制 String 類在堆空間中建立一個新的 String 物件。我們可以使用 intern()
方法將它放入池中或從具有相同值的字串池中引用其他 String 物件。
字串池本身也在堆上建立。
Version < Java SE 7
在 Java 7 之前,String
文字儲存在 PermGen
的方法區域中的執行時常量池中,該區域具有固定大小。
字串池也位於 PermGen
中。
Version >= Java SE 7
在 JDK 7 中,實現的字串不再分配在 Java 堆的永久生成中,而是分配在 Java 堆的主要部分(稱為年輕和舊的代)中,以及應用程式建立的其他物件。此更改將導致更多資料駐留在主 Java 堆中,並且永久生成中的資料更少,因此可能需要調整堆大小。由於這種變化,大多數應用程式只會看到堆使用中的相對較小的差異,但是載入許多類或大量使用
String.intern()
方法的較大應用程式將看到更顯著的差異。