關於String創建幾個對象的問題

   今天去筆試一家外包公司,有這個一道筆試題,自己答錯了,回來查看了一哈資料,分享一哈!

問:String s1="aa";        String s2="aa"; 這兩段代碼創建了幾個對象?

   本人回答的是3個。當時是這樣想的:首先String s1="aa"  會先在常量區找aa,沒有自己創建一個,這裏就一個對象了;s1我也想當然的覺得是創建了一個對象,這就兩個了;String s2="aa";此時aa在常量區已經存在了,就不會再創建,只創建s2,就是第三個對象,所以答案就是3個,我還信心滿滿地認爲這個答案是正確的,其實我錯了!


  String不在我們8大基本類型之中,是一個java.lang.String 的類,在Java中對象的創建都是通過構造器使用關鍵字new出來的,但是String也可以直接申明一個String s1,但是並沒有創建這個對象s1,只表示s1是String類型的,所以這題答案是:只穿件了一個對象aa.


             在Eclipse中Test一下:

       test1:            String s1="aa";       

                             String s2="aa";

                             System.out.println(s1==s2);//true

                    表示是s1和s2是同一個對象;

 test2:

          String s1=new String("aa");
        String s2=new String("aa");
        System.out.println(s1==s2);//false

System.out.println(s1.equals(s2));//true

   表示這裏的s1和s2是不同的兩個對象,只是說他們的對象內容是相等的。

 

       具體的String的理解,請參照下面的資料(這個資料是自己搜索相關技術文章找到的):

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):用於存儲對象

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章