一切從String str = new String("abc")說起...
這行代碼形式上很簡單,其實很復雜。有一個常見的Java筆試題就是問上面這行代碼創建了幾個String對象。
我剛開始很自然的覺得應該是創建了一個String對象,后來查閱資料,才發現,實際上創建了兩個String對象。下面說明為什么創建了兩個String對象。
首先,來了解一下Java中的字符串駐留池的概念。JVM為了提高性能,將一下兩種形式的字符串放在一個稱之為字符串駐留池的內存塊中:
形式一:String str = "abc";
形式二:"abc"
其實,形式一和形式二都是字符串的字面常量。所以,可以這樣理解,即把字符串的字面常量都放在了字符串駐留池中。對形式一來說,str其實就是引用的字符串駐留池中"abc"這個String對象。
如果有如下的兩行代碼:
String str1 = "abc";
String str2 = "abc";
那么,上面的兩行代碼創建了幾個String對象?答案是一個。根據我們剛才所述,那么第一行語句將在池中創建一個String對象,第二行會先在池中尋找是否有值與"abc"相同的String對象,如果有,就直接引用,沒有這在池中新建String對象。這下,就明白了為什么上面的兩行語句僅僅創建了一個String對象。
然后,讓我們來看一看String str = new String("abc")。我們先不討論到底創建了幾個String對象。我們在這里,比較一下這種new的方式和上面的直接賦值方式兩種創建String對象的不同,直接賦值的方式是在字符串駐留池中創建對象,但new這種方式是在堆中創建對象。即,new創建的String對象是不會放入字符串駐留池中的。如果一定要把某個通過new創建的字符串對象放入駐留池,可以使用intern()方法。如String strt = str.intern(),將把str的值放在駐留池中(當然,是在駐留池原來沒有這個值對應的String對象的情況下),并返回駐留池中String對象的引用。
現在,可以分析String str = new String("abc");創建了幾個String對象了:)很明顯,傳入的"abc"字符串字面常量在駐留池中創建了一個對象,new操作符在堆中創建了一個對象,所以,一共創建了兩個String對象。
對于Java中的其他類的對象的創建,應該沒有這種問題。看來,String對象還是挺特殊的...追根究底,我覺得還是因為字符串操作太多了,為了優化,不得已而為之。