String類型有兩種實例化的方法:
一種是直接賦值,如String str=“abc”;
另一種是通過new來實例化,如:String str=new String(“abc”);
通過一段測試代碼,我們發現:
public static void main(String[] args) {
String str1="abc";
String str2="abc";
String str3=new String("abc");
System.out.println(str1==str2);//true
System.out.println(str1==str3);//false
}
結果運行如圖:
爲什麼會這樣呢?
原因是:String類型直接實例化與new實例化對象是不同的;
在字符串中“==”比較的是字符串的地址;equals比較的是字符串的內容;
如果採用直接賦值 法:
在JVM底層實際上會自動維護一個對象池(字符串對象池),如果現在採用了直接賦值的模式進行String類的對象實例化操作,那麼該實例化對象(字符串內容)將自動保存到這個對象池之中。如果下次繼續引用直接賦值的模式聲明String類對象,此時對象池之中如若有指定內容,將直接進行引用;如若沒有,則開闢新的字符串對象而後將其保存在對象池之中以供下次使用;
如果採用構造方法new實例化一個對象:
該實例化對象卻不會入池,且即使對象池中有該字符串內容,它也會直接開闢新的內存存放該字符串,不會引用池中的任何字符串,與池中的內容完全無關;
所以針對上面的代碼:
String str1=“abc”; 因爲是直接賦值,所以就將該字符串內容直接入池了;
String str2=“abc”;直接賦值,發現字符串對象池中有該字符串內容,所以直接引用了該字符串;導致str1與str2是指向的同一個字符串對象;
String str3=new String(“abc”);new實例化對象,直接開闢新的內存空間,與上面的兩個字符串完全無關,
但是在String類中提供了方法入池操作 public String intern() ;
通過該方法,可以將用new實例化的字符串對象方入對象池中,其工作的過程就會和String直接賦值法工作的過程一樣;
public static void main(String[] args) {
String str1="qwe";
String str2=new String("qwe").intern();
System.out.println(str1==str2);//true
}
結果爲:
且兩種實例化對象的方式還有一點不同:
直接賦值法在實例化過程中只會創建一個堆內存空間:
如:String str=“Abc”;
在堆內存上創建一個字符串對象,使棧內存上的對象引用指向該字符串對象;
而通過構造方法實例化字符串對象的方法,在實例化過程中會創建兩個堆內存空間:
如: String str=new String(“Abc”);
在實例化的過程中,首先會創建一個堆內存空間(1)存儲字符串Abc,然後在new時,又創建了一個堆內存空間(2),存放該字符串對象,並使堆內存空間(1)成爲垃圾空間,被回收,接着使棧裏面的引用str指向該字符串對象;