Java中的String類別是一個很常用,但最不注意其細節的類,因此大多數面試會那這個類做文章。例如String str = new String("hello");開啟了幾個記憶體空間,String和StringBuffer的差別等等。下面就做一個我的理解:
String是一個被final修飾的類,它是不能被繼承的。 StringBuffer也是被final修飾的類別。
一、JVM記憶體劃分
在java中主要存在4塊內存,這些記憶體空間分別為:堆疊記憶體空間、堆疊記憶體空間、全域資料區、全域碼區
1、堆疊記憶體空間:保存所有的物件名稱(保所了所引用的堆疊記憶體空間的位址)
2、堆疊記憶體空間:儲存每個物件的特定內容
3、全域資料區:儲存static類型的資料屬性(全域資料)
4、全域程式碼區:儲存所有的方法定義
2:在堆疊記憶體重定義了一個a物件引用,先指向堆疊記憶體值為「hello」記憶體位址,然後再指向new之後堆疊記憶體為「hello」的位址。最後開啟了兩個空間,第一個空間沒有物件引用,會被JVM垃圾回收。
圖示如下:
理解上面的程式碼就不難理解以下這些程式碼:
package andy.string.test; /** * @author Zhang,Tianyou * version:2014-11-25 下午4:15:14 * * */ public class TestString { public static void main(String[] args){ String a = "hello"; String b = "hello"; String c = new String("hello"); String d = new String(); d = "hello"; String e = c; System.out.println("a==b ? " + (a== b)); System.out.println("a==c ? " + (c== b)); System.out.println("a==d ? " + (a== d)); System.out.println("a==e ? " + (a== e)); System.out.println("c==d ? " + (c== d)); System.out.println("c==e ? " + (c== e)); } }
##其中只有a==b==d 、 c=e。
解釋:
1、String每new一次堆記憶體不想等,而d在new分配完新位址之後,又放棄new之後的位址,指向a對應的記憶體位址,所以他們是相同的。
2、「hello」賦值此直接賦值方式所指向的堆疊記憶體空間是一樣的。 String在Java中使用了共享設計,在Java形成一個物件池,這個物件池可以保存多個對象,如果新實例化的物件已經在物件池中存在,就不在重複定義,直接從物件池中取出使用。所 以
存在的內容時,且將物件指向已執行實例的空間位址。
3、e直接指向C的記憶體空間。
4、因此使用String時,建議使用直接賦值方式,以縮小記憶體空間,提升效能。
三、String、StringBuffer和StringBuilder的區別
1、 String、StringBuffer、StringBuilder都是被final修飾的,是不能夠被繼承改寫的。
2、 String在實例化之後,其記憶體空間的內容大小是不能夠被修改的;而StringBuffer是一個線程安全的可變字元序列,在實例化之後可以動態的修改堆記憶體中的內容,所以記憶體長度和大小是可變的;StringBuilder實例化之後記憶體大小長度也是可變的,不
相同之處在於StringBuilder不是執行緒同步,因此操作起來必然比StringBuffer更有效率。
這是有人會想:
str += "andy";
而StringBuffer使用時,則只會開啟一塊記憶體空間,可使用append新增delete等作業內容。
String 每次產生物件都會對系統效能產生影響,特別當記憶體中無引用物件多了以後, JVM 的 GC 就會開始運作,那速度是一定會相當慢的。 而如果是使用 StringBuffer/StringBuilder 類別則結果就不一樣了,每次結果都會對 StringBuffer/StringBuilder 物件本身進行操作,而不是產生 新的對象,然後再改變物件參考。
因而在對一個字串循環賦值時,最好使用StringBuffer(線程安全)或StringBuilder,這樣可以節約內存,提高性能,切記
以上為Java中String、StringBuffer與StringBuilder的差異與堆疊記憶體分配的圖文所介紹的內容,並有更多相關內容請追蹤PHP中文網(www.php.cn)!