String str=new String("abc"); 緊接着這段代碼以後的每每是這個問題,那就是這行代碼究竟建立了幾個String對象呢?編程
相信你們對這道題並不陌生,由於有new,因此堆中必然有一個對象。另外,若是常量池中已有"abc",則不建立,沒有,則在常量池中建立。因此這句代碼,究竟在內存中建立一個仍是兩個對象,視狀況而定。優化
接下來咱們就從這道題展開,一塊兒回顧一下與建立String對象相關的一些JAVA知識。 spa
咱們能夠把上面這行代碼分紅String str、=、"abc"和new String()四部分來看待。String str只是定義了一個名爲str的String類型的變量,所以它並無建立對象;=是對變量str進行初始化,將某個對象的引用(或者叫句柄)賦值給 它,顯然也沒有建立對象;如今只剩下new String("abc")了。那麼,new String("abc")爲何又能被當作"abc"和new String()呢?code
咱們來看一下被咱們調用了的String的構造器: 對象
public String(String original) { //other code ... } 你們都知道,咱們經常使用的建立一個類的實例(對象)的方法有如下兩種:內存
1、使用new建立對象。 字符串
2、調用Class類的newInstance方法,利用反射機制建立對象。虛擬機
咱們正是使用new調用了String類的上 面那個構造器方法建立了一個對象,並將它的引用賦值給了str變量。同時咱們注意到,被調用的構造器方法接受的參數也是一個String對象,這個對象正 是"abc"。由此咱們又要引入另一種建立String對象的方式的討論——引號內包含文本。編譯
這種方式是String特有的,而且它與new的方式存在很大區別。 效率
String str = "abc";
毫無疑問,這行代碼建立了一個String對象。
String a = "abc"; String b="abc"; 那這裏呢?
答案仍是一個。
String a="ab"+"cd"; 再看看這裏呢?
答案是1個。這個只是建立了一個對象,在編譯時期已經進行優化了。說到這裏,咱們就須要引入對字符串池相關知識的回顧了。
在JAVA虛擬機(JVM)中存在着一個字符 串池,其中保存着不少String對象,而且能夠被共享使用,所以它提升了效率。因爲String類是final的,它的值一經建立就不可改變,所以咱們 不用擔憂String對象共享而帶來程序的混亂。字符串池由String類維護,咱們能夠調用intern()方法來訪問字符串池。
咱們再回頭看看String a="abc";,這行代碼被執行的時候,JAVA虛擬機首先在字符串池中查找是否已經存在了值爲"abc"的這麼一個對象,它的判斷依據是String 類equals(Object obj)方法的返回值。若是有,則再也不建立新的對象,直接返回已存在對象的引用;若是沒有,則先建立這個對象,而後把它加入到字符串池中,再將它的引用返 回。所以,咱們不難理解前面三個例子中頭兩個例子爲何是這個答案了。
只有使用引號包含文本的方式建立的 String對象之間使用「+」鏈接產生的新對象纔會被加入字符串池中。對於全部包含new方式新建對象(包括null)的「+」鏈接表達式,它所產生的 新對象都不會被加入字符串池中,對此咱們再也不贅述。所以咱們提倡你們用引號包含文本的方式來建立String對象以提升效率,實際上這也是咱們在編程中常 採用的。
棧(stack):主要保存基本類型(或者叫內置類型)(char、byte、short、int、long、float、double、boolean)和對象的引用,數據能夠共享,速度僅次於寄存器(register),快於堆。
堆(heap):用於存儲對象