String s=new String("abc")的引申
String str=new String("abc"); 緊接著這段代碼之後的往往是這個問題,那就是這行代碼究竟創建了幾個String對象呢?
相信大家對這道題並不陌生,答案也是眾所周知的,2個。
接下來我們就從這道題展開,一起回顧一下與創建String對象相關的一些JAVA知識。
我們可以把上面這行代碼分成String str、=、"abc"和new String()四部分來看待。String str只是定義了一個名為str的String類型的變量,因此它並沒有創建對象;=是對變量str進行初始化,將某個對象的引用(或者叫句柄)賦值給它,顯然也沒有創建對象;現在只剩下new String("abc")了。那麽,new String("abc")為什麽又能被看成"abc"和new String()呢?
我們來看一下被我們調用了的String的構造器:
public String(String original) { //other code ... } 大家都知道,我們常用的創建一個類的實例(對象)的方法有以下兩種:
一、使用new創建對象。
二、調用Class類的newInstance方法,利用反射機制創建對象。
我們正是使用new調用了String類的上面那個構造器方法創建了一個對象,並將它的引用賦值給了str變量。同時我們註意到,被調用的構造器方法接受的參數也是一個String對象,這個對象正是"abc"。由此我們又要引入另外一種創建String對象的方式的討論——引號內包含文本。
這種方式是String特有的,並且它與new的方式存在很大區別。
String str="abc";
毫無疑問,這行代碼創建了一個String對象。
String a="abc"; String b="abc"; 那這裏呢?
答案還是一個。
String a="ab"+"cd"; 再看看這裏呢?
答案是三個還是一個,有待確定。(在編譯之後String a="ab"+"cd";會變成String a="abcd";)說到這裏,我們就需要引入對字符串池相關知識的回顧了。
在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):用於存儲對象
看:
String s= "Hello ";
s= "Java ";
String s1= "Hello ";
String s2=new String( "Hello ");
啊,s所引用的string對象不是被修改了嗎?之前所說的不變性,去那裏了啊?
在jvm的工作過程中,會創建一片的內存空間專門存入string對象。我們把這片內存空間叫做string池。
String s= "Hello ";當jvm看到 "Hello ",在string池創建string對象存儲它,並將他的引用返回給s。
s= "Java ",當jvm看到 "Java ",在string池創建新的string對象存儲它,再把新建的string對象的引用返回給s。而原先的 "Hello "仍然在string池內。沒有消失,他是不能被修改的。
所以我們僅僅是改變了s的引用,而沒有改變他所引用的對象,因為string對象的值是不能被修改的。
(==,對於非基本類型,是比較兩引用是否引用內存中的同一個對象)
String s2=new String( "Hello ");jvm首先在string池內裏面看找不找到字符串 "Hello ",找到,不做任何事情,否則,創建新的string對象,放到string池裏面。由於遇到了new,還會在內存上(不是string池裏面)創建string對象存儲 "Hello ",並將內存上的(不是string池內的)string對象返回給s2。所以s==s2將返回false,不是引用同一個對象。
好現在我們看題目:
String s = new String( "xyz ");
首先在string池內找,找到?不創建string對象,否則創建, 這樣就一個string對象
遇到new運算符號了,在內存上創建string對象,並將其返回給s,又一個對象
所以總共是2個對象
String s=new String("abc")的引申