JDK1.8中JVM把String常量池移入了堆中,同時取消了「永久代」,改用元空間代替(Metaspace)
java中對String對象特殊對待,因此在heap區域分紅了兩塊,一塊是字符串常量池(String constant pool),用於存儲java字符串常量對象,另外一塊用於存儲普通對象及字符串對象。
string的建立有兩種方法:java
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"在內存中是否存在,都會在堆中開闢新空間。jvm
雖然new String()方法並不會把"abc」 加入到String constant pool中,可是能夠手動調用String.intern(),將new 出來的字符串對象加入到String constant pool中。spa
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"。.net
例:code
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());//堆裏 }
字符串在內存中的存儲狀況以下圖所示:對象
總結:blog
對於字符串:其對象的引用都是存儲在棧中的,若是是【編譯期已經建立好(直接用雙引號定義的)的就存儲在常量池中】,若是是【運行期(new出來的)才能肯定的就存儲在堆中】。對於equals相等的字符串,在常量池中永遠只有一份,在堆中有多份。內存
參考:字符串
https://blog.csdn.net/okyoung188/article/details/55506594get