String在記憶體中如何儲存(Java)
JDK1.8中JVM把String常量池移入了堆中,同時取消了“永久代”,改用元空間代替(Metaspace)
java中對String物件特殊對待,所以在heap區域分成了兩塊,一塊是字串常量池(String constant pool),用於儲存java字串常量物件,另一塊用於儲存普通物件及字串物件。
string的建立有兩種方法:
public static void main(String[] args) { String a = "abc"; //第一種 String b=new String("abc"); //第二種 String c = "abc"; System.out.println(a== b);//false System.out.println(a == c);//true }
對於第一種,此建立方法會在String constant pool中建立物件。jvm會首先在String constant pool 中尋找是否已經存在"abc"常量,如果沒有則建立該常量,並且將此常量的引用返回給String a;如果已有"abc" 常量,則直接返回String constant pool 中“abc” 的引用給String a。
對於第二種,jvm會直接在非String constant pool 中建立字串物件,然後把該物件引用返回給String b,並且不會把"abc” 加入到String constant pool中。new就是在堆中建立一個新的String物件,不管"abc"在記憶體中是否存在,都會在堆中開闢新空間。
雖然new String()方法並不會把"abc” 加入到String constant pool中,但是可以手動呼叫String.intern(),將new 出來的字串物件加入到String constant pool中。
String s1 = new String("abc"); String s2 = "abc"; System.out.println(s1 == s2); //false System.out.println(s1.intern() == s2); //true
當一個String例項呼叫intern()方法時,會查詢常量池中是否有相同的字串常量,如果有,則返回其的引用,如果沒有,則在常量池中增加一個等於str的字串並返回它的引用,由於s2已經在常量池中,所以s1.intern()不會再建立,而是直接引用同一個"aaa"。
例:
public static void main(String[] args) { String s1 = "abc";//字串常量池 String s2 = "xyz";//字串常量池 String s3 = "123";//字串常量池 String s4 = "A";//字串常量池 String s5 = new String("abc"); //堆裡 char[] c = {'J','A','V','A'}; String s6 = new String(c);//堆裡 String s7 = new String(new StringBuffer());//堆裡 }
字串在記憶體中的儲存情況如下圖所示:
總結:
對於字串:其物件的引用都是儲存在棧中的,如果是【編譯期已經建立好(直接用雙引號定義的)的就儲存在常量池中】,如果是【執行期(new出來的)才能確定的就儲存在堆中】。對於equals相等的字串,在常量池中永遠只有一份,在堆中有多份。
參考: