1. 程式人生 > >Java:String s=new String("abc")建立了幾個物件?

Java: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";   再看看這裡呢? 答案是三個。 說到這裡,我們就需要引入對字串池相關知識的回顧了。   在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):用於儲存 PS:對於String s5 = new String("Hello World"); 建立了幾個物件,我先前理解有誤。 總結各種看法,因為有new,所以堆中必然有一個物件。另外,如果常量池中已有"Hello World",則不建立,沒有,則在常量池中建立。所以這句程式碼,究竟在記憶體中建立一個還是兩個物件,視情況而定。 

=============================================================================================

你知道在java中除了8中基本型別外,其他的都是類物件以及其引用。所以 "xyz "在java中它是一個String物件.對於string類物件來說他的物件值是不能修改的,也就是具有不變性。  看:  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   s1= "Hello ";jvm首先在string池內裡面看找不找到字串 "Hello ",找到,返回他的引用給s1,否則,建立新的string物件,放到string池裡。這裡由於s= "Hello "了,物件已經被引用,所以依據規則s和s1都是引用同一個物件。所以   s==s1將返回true。(==,對於非基本型別,是比較兩引用是否引用記憶體中的同一個物件)  String   s2=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個物件 

一個例子:  public class Test  {  public static void main(String [] args)  {  String s1=new String("test");//建立2個物件,一個Class和一個堆裡面  String s2="test";//建立1個物件,s2指向pool裡面的"test"物件  String s3="test";//建立0個物件,指向s2指想pool裡面的那個物件  String s4=s2;//建立0個物件,指向s2,s3指想pool裡面的那個物件  String s5=new String("test");//建立1個物件在堆裡面,注意,與s1沒關係  System.out.println(s2=="test");//true s2=="test"很明顯true  System.out.println(s2==s3);//true,因為指向的都是pool裡面的那個"test"  System.out.println(s2==s4);//true,同上,那麼s3和s4...:)  System.out.println(s1==s5);//false,很明顯,false  System.out.println(s1==s2);//false,指向的物件不一樣,下面再說  System.out.println(s1=="test");//false,難道s1!="tset"?下面再說  System.out.println("---------------");  s1=s2;  System.out.println(s1=="test");//true,下面說  }  }  說明:1,System.out.println(s1==s2);很明顯,s2指向的物件"test"是在pool裡面,而s1指向的是堆裡面的"test"物件(s1指向的記憶體區),所以返回false.  2,System.out.println(s1=="test");s1指向的是堆裡面的"test"物件(s1指向的記憶體區),而"test"是程式 剛剛建立的(其實是共用pool裡面的那個已經建立了的"test"物件,也就是我們s2="test"時候,在pool裡面建立的),所以s1指向的堆 裡的"test"物件  和"test"(pool裡面)並不是一樣個物件,所以返回false.  3,當我們s1=s2;的時候,很明顯,把s2的指給了s1,s1指向pool裡面的"test",這個時候,s2也指向了pool裡面的"test"對 象了,當System.out.println(s1=="test");時候,java虛擬機器建立"test"物件,注意,其實沒建立,和前面講的一 樣,公用s1="test"建立的"test"物件(pool裡面的),所以,s1=="test"(pool裡面的),同 樣,s1=s2=s3=s4!  而為什麼在網上都說String s=new String("test");建立了2個物件?那可能因為它就寫這麼一句程式碼,誤讓人預設的認為執行程式碼之前並不例項任何一個String物件過(也許 很多人不會這麼想,),跟著別人或者不經思考的就說2個,斟是說存放在棧記憶體中專門存放String物件引用的s變數是一個物件!實在不可原諒!