java string对象创建对象_Java String 创建了几个对象
我們首先來(lái)看一段代碼:
Java代碼
String str=new String("abc");
緊接著這段代碼之后的往往是這個(gè)問(wèn)題,那就是這行代碼究竟創(chuàng)建了幾個(gè)String對(duì)象呢?相信大家對(duì)這道題并不陌生,答案也是眾所周知的,2個(gè)。接下來(lái)我們就從這道題展開(kāi),一起回顧一下與創(chuàng)建String對(duì)象相關(guān)的一些JAVA知識(shí)。
我們可以把上面這行代碼分成String str、=、"abc"和new String()四部分來(lái)看待。String str只是定義了一個(gè)名為str的String類型的變量,因此它并沒(méi)有創(chuàng)建對(duì)象;=是對(duì)變量str進(jìn)行初始化,將某個(gè)對(duì)象的引用(或者叫句柄)賦值給它,顯然也沒(méi)有創(chuàng)建對(duì)象;現(xiàn)在只剩下new String("abc")了。那么,new String("abc")為什么又能被看成"abc"和new String()呢?我們來(lái)看一下被我們調(diào)用了的String的構(gòu)造器:
Java代碼
public String(String original) {
//other code ...
}
大家都知道,我們常用的創(chuàng)建一個(gè)類的實(shí)例(對(duì)象)的方法有以下兩種:
使用new創(chuàng)建對(duì)象。
調(diào)用Class類的newInstance方法,利用反射機(jī)制創(chuàng)建對(duì)象。
我們正是使用new調(diào)用了String類的上面那個(gè)構(gòu)造器方法創(chuàng)建了一個(gè)對(duì)象,并將它的引用賦值給了str變量。同時(shí)我們注意到,被調(diào)用的構(gòu)造器方法接受的參數(shù)也是一個(gè)String對(duì)象,這個(gè)對(duì)象正是"abc"。由此我們又要引入另外一種創(chuàng)建String對(duì)象的方式的討論——引號(hào)內(nèi)包含文本。
這種方式是String特有的,并且它與new的方式存在很大區(qū)別。
Java代碼
String str="abc";
毫無(wú)疑問(wèn),這行代碼創(chuàng)建了一個(gè)String對(duì)象。
Java代碼
String a="abc";
String b="abc";
那這里呢?答案還是一個(gè)。
Java代碼
String a="ab"+"cd";
再看看這里呢?答案是三個(gè)。有點(diǎn)奇怪嗎?說(shuō)到這里,我們就需要引入對(duì)字符串池相關(guān)知識(shí)的回顧了。
在JAVA虛擬機(jī)(JVM)中存在著一個(gè)字符串池,其中保存著很多String對(duì)象,并且可以被共享使用,因此它提高了效率。由于String類是final的,它的值一經(jīng)創(chuàng)建就不可改變,因此我們不用擔(dān)心String對(duì)象共享而帶來(lái)程序的混亂。字符串池由String類維護(hù),我們可以調(diào)用intern()方法來(lái)訪問(wèn)字符串池。
我們?cè)倩仡^看看String a="abc";,這行代碼被執(zhí)行的時(shí)候,JAVA虛擬機(jī)首先在字符串池中查找是否已經(jīng)存在了值為"abc"的這么一個(gè)對(duì)象,它的判斷依據(jù)是String類equals(Object obj)方法的返回值。如果有,則不再創(chuàng)建新的對(duì)象,直接返回已存在對(duì)象的引用;如果沒(méi)有,則先創(chuàng)建這個(gè)對(duì)象,然后把它加入到字符串池中,再將它的引用返回。因此,我們不難理解前面三個(gè)例子中頭兩個(gè)例子為什么是這個(gè)答案了。
對(duì)于第三個(gè)例子:
Java代碼
String a="ab"+"cd";
"ab"和"cd"分別創(chuàng)建了一個(gè)對(duì)象,它們經(jīng)過(guò)“+”連接后又創(chuàng)建了一個(gè)對(duì)象"abcd",因此一共三個(gè),并且它們都被保存在字符串池里了。
現(xiàn)在問(wèn)題又來(lái)了,是不是所有經(jīng)過(guò)“+”連接后得到的字符串都會(huì)被添加到字符串池中呢?我們都知道“==”可以用來(lái)比較兩個(gè)變量,它有以下兩種情況:
如果比較的是兩個(gè)基本類型(char,byte,short,int,long,float,double,boolean),則是判斷它們的值是否相等。
如果表較的是兩個(gè)對(duì)象變量,則是判斷它們的引用是否指向同一個(gè)對(duì)象。
下面我們就用“==”來(lái)做幾個(gè)測(cè)試。為了便于說(shuō)明,我們把指向字符串池中已經(jīng)存在的對(duì)象也視為該對(duì)象被加入了字符串池:
Java代碼
public class StringTest {
public static void main(String[] args) {
String a = "ab";// 創(chuàng)建了一個(gè)對(duì)象,并加入字符串池中
System.out.println("String a = "ab";");
String b = "cd";// 創(chuàng)建了一個(gè)對(duì)象,并加入字符串池中
System.out.println("String b = "cd";");
String c = "abcd";// 創(chuàng)建了一個(gè)對(duì)象,并加入字符串池中
String d = "ab" + "cd";
// 如果d和c指向了同一個(gè)對(duì)象,則說(shuō)明d也被加入了字符串池
if (d == c) {
System.out.println(""ab"+"cd" 創(chuàng)建的對(duì)象 "加入了" 字符串池中");
}
// 如果d和c沒(méi)有指向了同一個(gè)對(duì)象,則說(shuō)明d沒(méi)有被加入字符串池
else {
System.out.println(""ab"+"cd" 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中");
}
String e = a + "cd";
// 如果e和c指向了同一個(gè)對(duì)象,則說(shuō)明e也被加入了字符串池
if (e == c) {
System.out.println(" a +"cd" 創(chuàng)建的對(duì)象 "加入了" 字符串池中");
}
// 如果e和c沒(méi)有指向了同一個(gè)對(duì)象,則說(shuō)明e沒(méi)有被加入字符串池
else {
System.out.println(" a +"cd" 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中");
}
String f = "ab" + b;
// 如果f和c指向了同一個(gè)對(duì)象,則說(shuō)明f也被加入了字符串池
if (f == c) {
System.out.println(""ab"+ b 創(chuàng)建的對(duì)象 "加入了" 字符串池中");
}
// 如果f和c沒(méi)有指向了同一個(gè)對(duì)象,則說(shuō)明f沒(méi)有被加入字符串池
else {
System.out.println(""ab"+ b 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中");
}
String g = a + b;
// 如果g和c指向了同一個(gè)對(duì)象,則說(shuō)明g也被加入了字符串池
if (g == c) {
System.out.println(" a + b 創(chuàng)建的對(duì)象 "加入了" 字符串池中");
}
// 如果g和c沒(méi)有指向了同一個(gè)對(duì)象,則說(shuō)明g沒(méi)有被加入字符串池
else {
System.out.println(" a + b 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中");
}
}
}
運(yùn)行結(jié)果如下:
String a = "ab";
String b = "cd";
"ab"+"cd" 創(chuàng)建的對(duì)象 "加入了" 字符串池中
a +"cd" 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中
"ab"+ b 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中
a + b 創(chuàng)建的對(duì)象 "沒(méi)加入" 字符串池中
從上面的結(jié)果中我們不難看出,只有使用引號(hào)包含文本的方式創(chuàng)建的String對(duì)象之間使用“+”連接產(chǎn)生的新對(duì)象才會(huì)被加入字符串池中。對(duì)于所有包含new方式新建對(duì)象(包括null)的“+”連接表達(dá)式,它所產(chǎn)生的新對(duì)象都不會(huì)被加入字符串池中,對(duì)此我們不再贅述。因此我們提倡大家用引號(hào)包含文本的方式來(lái)創(chuàng)建String對(duì)象以提高效率,實(shí)際上這也是我們?cè)诰幊讨谐2捎玫摹?/p>
接下來(lái)我們?cè)賮?lái)看看intern()方法,它的定義如下:
Java代碼
public native String intern();
這是一個(gè)本地方法。在調(diào)用這個(gè)方法時(shí),JAVA虛擬機(jī)首先檢查字符串池中是否已經(jīng)存在與該對(duì)象值相等對(duì)象存在,如果有則返回字符串池中對(duì)象的引用;如果沒(méi)有,則先在字符串池中創(chuàng)建一個(gè)相同值的String對(duì)象,然后再將它的引用返回。
我們來(lái)看這段代碼:
Java代碼
public class StringInternTest {
public static void main(String[] args) {
// 使用char數(shù)組來(lái)初始化a,避免在a被創(chuàng)建之前字符串池中已經(jīng)存在了值為"abcd"的對(duì)象
String a = new String(new char[] { 'a', 'b', 'c', 'd' });
String b = a.intern();
if (b == a) {
System.out.println("b被加入了字符串池中,沒(méi)有新建對(duì)象");
} else {
System.out.println("b沒(méi)被加入字符串池中,新建了對(duì)象");
}
}
}
運(yùn)行結(jié)果:
b沒(méi)被加入字符串池中,新建了對(duì)象
如果String類的intern()方法在沒(méi)有找到相同值的對(duì)象時(shí),是把當(dāng)前對(duì)象加入字符串池中,然后返回它的引用的話,那么b和a指向的就是同一個(gè)對(duì)象;否則b指向的對(duì)象就是JAVA虛擬機(jī)在字符串池中新建的,只是它的值與a相同罷了。上面這段代碼的運(yùn)行結(jié)果恰恰印證了這一點(diǎn)。
最后我們?cè)賮?lái)說(shuō)說(shuō)String對(duì)象在JAVA虛擬機(jī)(JVM)中的存儲(chǔ),以及字符串池與堆(heap)和棧(stack)的關(guān)系。我們首先回顧一下堆和棧的區(qū)別:
棧(stack):主要保存基本類型(或者叫內(nèi)置類型)(char、byte、short、int、long、float、double、boolean)和對(duì)象的引用,數(shù)據(jù)可以共享,速度僅次于寄存器(register),快于堆。
堆(heap):用于存儲(chǔ)對(duì)象。
我們查看String類的源碼就會(huì)發(fā)現(xiàn),它有一個(gè)value屬性,保存著String對(duì)象的值,類型是char[],這也正說(shuō)明了字符串就是字符的序列。
當(dāng)執(zhí)行String a="abc";時(shí),JAVA虛擬機(jī)會(huì)在棧中創(chuàng)建三個(gè)char型的值'a'、'b'和'c',然后在堆中創(chuàng)建一個(gè)String對(duì)象,它的值(value)是剛才在棧中創(chuàng)建的三個(gè)char型值組成的數(shù)組{'a','b','c'},最后這個(gè)新創(chuàng)建的String對(duì)象會(huì)被添加到字符串池中。如果我們接著執(zhí)行String b=new String("abc");代碼,由于"abc"已經(jīng)被創(chuàng)建并保存于字符串池中,因此JAVA虛擬機(jī)只會(huì)在堆中新創(chuàng)建一個(gè)String對(duì)象,但是它的值(value)是共享前一行代碼執(zhí)行時(shí)在棧中創(chuàng)建的三個(gè)char型值值'a'、'b'和'c'。
說(shuō)到這里,我們對(duì)于篇首提出的String str=new String("abc")為什么是創(chuàng)建了兩個(gè)對(duì)象這個(gè)問(wèn)題就已經(jīng)相當(dāng)明了了
總結(jié)
以上是生活随笔為你收集整理的java string对象创建对象_Java String 创建了几个对象的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: “不解心款曲”上一句是什么
- 下一篇: java 反射 new class_Ja