答案是眾所周知的,2個哭靖。
接下來我們就從這道題展開具垫,一起回顧一下與創(chuàng)建String對象相關(guān)的一些JAVA知識。
我們可以把上面這行代碼分成String str试幽、=筝蚕、"abc"和new String()四部分來看待。String str只是定義了一個名為str的String類型的變量铺坞,因此它并沒有創(chuàng)建對象起宽;=是對變量str進行初始化,將某個對象的引用(或者叫句柄)賦值給它济榨,顯然也沒有創(chuàng)建對象坯沪;現(xiàn)在只剩下new String("abc")了。那么擒滑,new String("abc")為什么又能被看成"abc"和new String()呢腐晾?
我們來看一下被我們調(diào)用了的String的構(gòu)造器:
public String(String original) { //other code ... }
大家都知道,我們常用的創(chuàng)建一個類的實例(對象)的方法有以下兩種:
- 一丐一、使用new創(chuàng)建對象纱烘。
- 二椎眯、調(diào)用Class類的newInstance方法捉撮,利用反射機制創(chuàng)建對象箩绍。
我們正是使用new調(diào)用了String類的上面那個構(gòu)造器方法創(chuàng)建了一個對象畅哑,并將它的引用賦值給了str變量汹胃。同時我們注意到勋陪,被調(diào)用的構(gòu)造器方法接受的參數(shù)也是一個String對象揩瞪,這個對象正是"abc"疹鳄。由此我們又要引入另外一種創(chuàng)建String對象的方式的討論——引號內(nèi)包含文本拧略。
這種方式是String特有的,并且它與new的方式存在很大區(qū)別瘪弓。
String str="abc";
毫無疑問垫蛆,這行代碼創(chuàng)建了一個String對象。
String a="abc"; String b="abc"; 那這里呢腺怯?
答案還是一個袱饭。
String a="ab"+"cd"; 再看看這里呢?
答案是三個呛占。
說到這里虑乖,我們就需要引入對字符串池相關(guān)知識的回顧了。
在JAVA虛擬機(JVM)中存在著一個字符串池晾虑,其中保存著很多String對象疹味,并且可以被共享使用仅叫,因此它提高了效率。由于String類是final的糙捺,它的值一經(jīng)創(chuàng)建就不可改變诫咱,因此我們不用擔(dān)心String對象共享而帶來程序的混亂。字符串池由String類維護洪灯,我們可以調(diào)用intern()方法來訪問字符串池坎缭。
我們再回頭看看String a="abc";,這行代碼被執(zhí)行的時候婴渡,JAVA虛擬機首先在字符串池中查找是否已經(jīng)存在了值為"abc"的這么一個對象幻锁,它的判斷依據(jù)是String類equals(Object obj)方法的返回值。如果有边臼,則不再創(chuàng)建新的對象哄尔,直接返回已存在對象的引用;如果沒有柠并,則先創(chuàng)建這個對象岭接,然后把它加入到字符串池中,再將它的引用返回臼予。因此鸣戴,我們不難理解前面三個例子中頭兩個例子為什么是這個答案了。
只有使用引號包含文本的方式創(chuàng)建的String對象之間使用“+”連接產(chǎn)生的新對象才會被加入字符串池中粘拾。對于所有包含new方式新建對象(包括null)的“+”連接表達式窄锅,它所產(chǎn)生的新對象都不會被加入字符串池中,對此我們不再贅述缰雇。因此我們提倡大家用引號包含文本的方式來創(chuàng)建String對象以提高效率入偷,實際上這也是我們在編程中常采用的。
棧(stack):主要保存基本類型(或者叫內(nèi)置類型)(char械哟、byte疏之、short、int暇咆、long锋爪、float、double爸业、boolean)和對象的引用其骄,數(shù)據(jù)可以共享,速度僅次于寄存器(register)扯旷,快于堆年栓。
堆(heap):用于存儲對象