JAVA面試題解惑系列(二)_第1頁
JAVA面試題解惑系列(二)_第2頁
JAVA面試題解惑系列(二)_第3頁
JAVA面試題解惑系列(二)_第4頁
JAVA面試題解惑系列(二)_第5頁
已閱讀5頁,還剩3頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

-JAVA程序員JAVA工程師面試必看JAVA面試題解惑系列(二)一一到底創(chuàng)建了幾個(gè)String對(duì)象?關(guān)鍵字:java面試題string創(chuàng)建幾個(gè)對(duì)象作者:臧圩人(zangweiren)網(wǎng)址:>>>轉(zhuǎn)載請(qǐng)注明出處!<<<我們首先來看一段代碼:Java代碼-■Stringstr=newString("abc");緊接著這段代碼之后的往往是這個(gè)問題,那就是這行代碼究竟創(chuàng)建了幾個(gè)String對(duì)象呢?相信大家對(duì)這道題并不陌生,答案也是眾所周知的,2個(gè)。接下來我們就從這道題展開,一起回顧一下與創(chuàng)建String對(duì)象相關(guān)的一些JAVA知識(shí)。我們可以把上面這行代碼分成Stringstr、=、"abc"和newString()四部分來看待。Stringstr只是定義了一個(gè)名為str的String類型的變量,因此它并沒有創(chuàng)建對(duì)象;=是對(duì)變量str進(jìn)行初始化,將某個(gè)對(duì)象的引用(或者叫句柄)賦值給它,顯然也沒有創(chuàng)建對(duì)象;現(xiàn)在只剩下newString("abc")了。那么,newString("abc")為什么又能被看成"abc"和newString()呢?我們來看一下被我們調(diào)用了的String的構(gòu)造器:Java代碼-■publicString(Stringoriginal){//othercode...}大家都知道,我們常用的創(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代碼Stringstr="abc";毫無疑問,這行代碼創(chuàng)建了一個(gè)String對(duì)象。Java代碼Stringa="abc";Stringb="abc";

那這里呢?答案還是一個(gè)。Java代碼Stringa="ab"+"cd";再看看這里呢?答案仍是一個(gè)。有點(diǎn)奇怪嗎?說到這里,我們就需要引入對(duì)字符串池相關(guān)知識(shí)的回顧了。在JAVA虛擬機(jī)(JVM)中存在著一個(gè)字符串池,其中保存著很多String對(duì)象,并且可以被共享使用,因此它提高了效率。由于String類是final的,它的值一經(jīng)創(chuàng)建就不可改變,因此我們不用擔(dān)心String對(duì)象共享而帶來程序的混亂。字符串池由String類維護(hù),我們可以調(diào)用intern()方法來訪問字符串池。我們?cè)倩仡^看看Stringa="abc";,這行代碼被執(zhí)行的時(shí)候,JAVA虛擬機(jī)首先在字符串池中查找是否已經(jīng)存在了值為"abc"的這么一個(gè)對(duì)象,它的判斷依據(jù)是String類equals(Objectobj)方法的返回值。如果有,則不再創(chuàng)建新的對(duì)象,直接返回已存在對(duì)象的引用;如果沒有,則先創(chuàng)建這個(gè)對(duì)象,然后把它加入到字符串池中,再將它的引用返回。因此,我們不難理解前面三個(gè)例子中頭兩個(gè)例子為什么是這個(gè)答案了。對(duì)于第三個(gè)例子:Java代碼Stringa="ab"+"cd";由于常量的值在編譯的時(shí)候就被確定了。在這里,"ab"和"cd"都是常量,因此變量a的值在編譯時(shí)就可以確定。這行代碼編譯后的效果等同于:Java代碼—Stringa="abcd";因此這里只創(chuàng)建了一個(gè)對(duì)象"abcd",并且它被保存在字符串池里了?,F(xiàn)在問題又來了,是不是所有經(jīng)過“+”連接后得到的字符串都會(huì)被添加到字符串池中呢?我們都知道“==”可以用來比較兩個(gè)變量,它有以下兩種情況:如果比較的是兩個(gè)基本類型(char,byte,short,int,long,float,double,boolean),則是判斷它們的值是否相等。如果表較的是兩個(gè)對(duì)象變量,則是判斷它們的引用是否指向同一個(gè)對(duì)象。下面我們就用“==”來做幾個(gè)測試。為了便于說明,我們把指向字符串池中已經(jīng)存在的對(duì)象也視為該對(duì)象被加Java代碼....10.publicstaticvoidmain(String[]args){Stringa="ab";//創(chuàng)建了一個(gè)對(duì)象,并加入字符串池中System.out.println("Stringa=\"ab\";");Stringb="cd";//創(chuàng)建了一個(gè)對(duì)象,并加入字符串池中System.out.println("Stringb=\"cd\";");Stringc="abed";//創(chuàng)建了一個(gè)對(duì)象,并加入字符串池中Stringd="ab"+"cd";//如果d和c指向了同一個(gè)對(duì)象,則說明d也被加入了字符串池

if(d==c){System.out.println("\"ab\"+\"cd\"創(chuàng)建的對(duì)象\"加入了\"字符串池中");TOC\o"1-5"\h\z}//如果d和c沒有指向了同一個(gè)對(duì)象,則說明d沒有被加入字符串池else{System.out.println("\"ab\"+\"cd\"創(chuàng)建的對(duì)象\"沒加入\"字符串池中”);}18.Stringe=a+"cd";//如果e和c指向了同一個(gè)對(duì)象,則說明e也被加入了字符串池if(e==c) {System.out.println(”a+\"cd\"創(chuàng)建的對(duì)象\"加入了\"字符串池中”);}//如果e和c沒有指向了同一個(gè)對(duì)象,則說明e沒有被加入字符串池else{System.out.println("a+\"cd\"創(chuàng)建的對(duì)象\"沒加入\"字符串池中");}28.Stringf="ab"+b;//如果f和c指向了同一個(gè)對(duì)象,則說明f也被加入了字符串池if(f== c){System.out.println("\"ab\"+b創(chuàng)建的對(duì)象\"加入了\"字符串池中");}//如果f和c沒有指向了同一個(gè)對(duì)象,則說明f沒有被加入字符串池else{System.out.println("\"ab\"+b創(chuàng)建的對(duì)象\"沒加入\"字符串池中");}38.Stringg=a+b;//如果g和c指向了同一個(gè)對(duì)象,則說明g也被加入了字符串池if(g==c){System.out.println("a+b創(chuàng)建的對(duì)象\"加入了\"字符串池中");TOC\o"1-5"\h\z}//如果g和c沒有指向了同一個(gè)對(duì)象,則說明g沒有被加入字符串池else{System.out.println("a+b創(chuàng)建的對(duì)象\"沒加入\"字符串池中");}}}運(yùn)行結(jié)果如下:Stringa="ab";Stringb="cd";"ab"+"cd"創(chuàng)建的對(duì)象"加入了"字符串池中a+"cd"創(chuàng)建的對(duì)象"沒加入"字符串池中"ab"+b創(chuàng)建的對(duì)象"沒加入"字符串池中a+b創(chuàng)建的對(duì)象"沒加入"字符串池中從上面的結(jié)果中我們不難看出,只有使用引號(hào)包含文本的方式創(chuàng)建的String對(duì)象之間使用“+”連接產(chǎn)生的新對(duì)象才會(huì)被加入字符串池中。對(duì)于所有包含new方式新建對(duì)象(包括null)的“+”連接表達(dá)式,它所產(chǎn)生的新對(duì)象都不會(huì)被加入字符串池中,對(duì)此我們不再贅述。但是有一種情況需要引起我們的注意。請(qǐng)看下面的代碼:Java代碼1. publicclassStringStaticTest{//常量ApublicstaticfinalStringA="ab";4.//常量BpublicstaticfinalStringB="cd";7.publicstaticvoidmain(String[]args){//將兩個(gè)常量用+連接對(duì)s進(jìn)行初始化Strings=A+B;Stringt="abcd";if(s==t){System.out.println("s等于t,它們是同一個(gè)對(duì)象");}else{System.out.println("s不等于t,它們不是同一個(gè)對(duì)象");}}}這段代碼的運(yùn)行結(jié)果如下:s等于t,它們是同一個(gè)對(duì)象這又是為什么呢?原因是這樣的,對(duì)于常量來講,它的值是固定的,因此在編譯期就能被確定了,而變量的值只有到運(yùn)行時(shí)才能被確定,因?yàn)檫@個(gè)變量可以被不同的方法調(diào)用,從而可能引起值的改變。在上面的例子中,A和B都是常量,值是固定的,因此s的值也是固定的,它在類被編譯時(shí)就已經(jīng)確定了。也就是說:Java代碼1.Strings=A+B;等同于:Java代碼—1.Strings="ab"+"cd";我對(duì)上面的例子稍加改變看看會(huì)出現(xiàn)什么情況:Java代碼publicclassStringStaticTest{//常量ApublicstaticfinalStringA;4.//常量BpublicstaticfinalStringB;7.static{A="ab";B="cd";}12.publicstaticvoidmain(String[]args){//將兩個(gè)常量用+連接對(duì)s進(jìn)行初始化15.Strings=A+B;16.Stringt="abcd";17.if(s==t){18.System.out.println("s等于t,它們是同一個(gè)對(duì)象");19.}else{20.System.out.println("s不等于t,它們不是同一個(gè)對(duì)象”);21.}22.}23.}它的運(yùn)行結(jié)果是這樣:s不等于t,它們不是同一個(gè)對(duì)象只是做了一點(diǎn)改動(dòng),結(jié)果就和剛剛的例子恰好相反。我們?cè)賮矸治鲆幌?。A和B雖然被定義為常量(只能被賦值一次),但是它們都沒有馬上被賦值。在運(yùn)算出s的值之前,他們何時(shí)被賦值,以及被賦予什么樣的值,都是個(gè)變數(shù)。因此A和B在被賦值之前,性質(zhì)類似于一個(gè)變量。那么s就不能在編譯期被確定,而只能在運(yùn)行時(shí)被創(chuàng)建了。由于字符串池中對(duì)象的共享能夠帶來效率的提高,因此我們提倡大家用引號(hào)包含文本的方式來創(chuàng)建String對(duì)象,實(shí)際上這也是我們?cè)诰幊讨谐2捎玫?。接下來我們?cè)賮砜纯磇ntern()方法,它的定義如下:Java代碼1.publicnativeStringintern();這是一個(gè)本地方法。在調(diào)用這個(gè)方法時(shí),JAVA虛擬機(jī)首先檢查字符串池中是否已經(jīng)存在與該對(duì)象值相等對(duì)象存在,如果有則返回字符串池中對(duì)象的引用;如果沒有,則先在字符串池中創(chuàng)建一個(gè)相同值的String對(duì)象,然后再將它的引用返回。我們來看這段代碼:Java代碼publicclassStringInternTest{publicstaticvoidmain(String[]args){//使用char數(shù)組來初始化a,避免在a被創(chuàng)建之前字符串池中已經(jīng)存在了值為"abed"的對(duì)象Stringa=newString(newchar[]{'a','b','c','d'});Stringb = ern();if(b== a) {System.out.println("b被加入了字符串池中,沒有新建對(duì)象");}else{System.out.println("b沒被加入字符串池中,新建了對(duì)象”);}}}運(yùn)行結(jié)果:b沒被加入字符串池中,新建了對(duì)象如果String類的intern()方法在沒有找到相同值的對(duì)象時(shí),是把當(dāng)前對(duì)象加入字符串池中,然后返回它的引用的話,那么b和a指向的就是同一個(gè)對(duì)象;否則b指向的對(duì)象就是JAVA虛擬機(jī)在字符串池中新建的,只是它的值與a相同罷了。上面這段代碼的運(yùn)行結(jié)果恰恰印證了這一點(diǎn)。最后我們?cè)賮碚f說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[],這也正說明了字符串就是字符的序列。當(dāng)執(zhí)行Stringa="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í)行Stringb=newString("abc");代碼,由于"abc"已經(jīng)被創(chuàng)建并保存于字符串池中,因此JAVA虛擬機(jī)只會(huì)在堆中新創(chuàng)建一個(gè)String對(duì)象,但是它的值(value)是共享前一行代碼執(zhí)行時(shí)在棧中創(chuàng)建的三個(gè)char型值值'a'、’b'和'c'。說到這里,我們對(duì)于篇首提出的Stringstr=newString("abc")為什么是創(chuàng)建了兩個(gè)對(duì)象這個(gè)問題就已經(jīng)相當(dāng)明了了。?18:45?瀏覽(4398)評(píng)論(58)分類:JAVA面試題解惑系列收藏相關(guān)推薦評(píng)論臧圩人4小時(shí)前回復(fù)disorder:因?yàn)槭鞘褂胣ew創(chuàng)建的,因此沒有加入到字符串池中,但是你可以調(diào)用intern()方法來手動(dòng)實(shí)現(xiàn)這一步disorder4小時(shí)前請(qǐng)問一下為什么這里a就沒有被加入到池中呢?Java代碼1.Stringa=newString(newchar[]{'a','b','c','d'});臧圩人前天回復(fù)viMory:你引用的那段話所講的是對(duì)的,但是在我所舉的例子中,由于我給出的示例代碼前沒有其它代碼執(zhí)行,因此"abc"不會(huì)被創(chuàng)建出來viMory2008-07-14引用這個(gè)還與具體的條件相關(guān),如果在String池中沒有“abc”對(duì)象存在那么就會(huì)創(chuàng)建兩個(gè)對(duì)象,如果池中已經(jīng)存在“abc”對(duì)象的話,那么就只是創(chuàng)建一個(gè)對(duì)象,所以這個(gè)問題要看具體的條件才能下結(jié)論我也同意這句,已經(jīng)存在的話就是一個(gè)對(duì)象了。LZ你認(rèn)為有可能不?Bluesnails2008-07-14看了前兩章,總結(jié)的很詳細(xì)啊,受教了?zm26934502008-07-14好貼,頂起來臧圩人2008-07-13回復(fù)chq32:這位朋友,不知你是沒看全還是沒看仔細(xì)我很明確地說了Stringstr只是定義了一個(gè)變量并沒有創(chuàng)建對(duì)象,真正創(chuàng)建對(duì)象的是"abc"和newString。chq322008-07-13我總覺得是一個(gè)對(duì)象。Stringstr=newString("abc");用"人"來比喻的話,,"str"相當(dāng)于人的身證證,"abc"相當(dāng)于人的肉身你能說是兩個(gè)人嗎??我不解如果按樓主說的是兩個(gè)對(duì)象,那我看所有的對(duì)象都是兩個(gè)對(duì)象了臧圩人2008-07-09回復(fù)狂放不羈:你說得對(duì)。不過我寫這系列文章的目的是面試題解惑,和鞏固基礎(chǔ)知識(shí),如果想要做好J2EE企業(yè)級(jí)開發(fā),就需要更進(jìn)一步的學(xué)習(xí)了狂放不羈2008-07-08呵呵,這種考題也就只能考考J2SE基礎(chǔ)。做J2EE企業(yè)級(jí)開發(fā),設(shè)計(jì)模式,00思想才是重點(diǎn)。臧圩人2008-07-06回復(fù)Unmi:呵呵,一個(gè)人的能力固然不是單憑面試就能夠完全考出來的,但是出面試題不失為一個(gè)不錯(cuò)的考查方法,而分00.析面試題也不失為一個(gè)有針對(duì)性的好的學(xué)習(xí)途徑Unmi2008-07-06我覺得出這個(gè)題目的人很無聊,分析這個(gè)問題的更是無聊,有意思嗎?迂腐臧圩人2008-07-06回復(fù)zc2yhy:總結(jié)的很好我對(duì)于字符串池是這么理解的,它是內(nèi)存中的一塊內(nèi)存區(qū)域,作用可以類比于數(shù)組(當(dāng)然,字符串池并不是對(duì)oc.象),字符串池中保存的只是對(duì)象的引用,實(shí)際的對(duì)象只在堆中保存一份。zc,2yhy2008-07-05讓小弟來小結(jié)一下這篇文章所說的事情吧堆和棧的概念。編譯器也是很機(jī)械化的,只能一行行的讀代碼,所以,在有的時(shí)候看似為靜態(tài)的值,其實(shí)編譯器是看不出來的,它也只能當(dāng)機(jī)立斷得判斷。3?看完后感覺在lz所說的字符串池中存儲(chǔ)的其實(shí)也是基本數(shù)據(jù)類型char的數(shù)組或者說序列char[],在String類中將其包裝。在vb還是c#中我忘了,就區(qū)分了這兩種字符串的概念,分為基本類型string和對(duì)象類型String(注意大小寫)。4?在這里完全能感受到創(chuàng)作一個(gè)完整、封閉的語言是多么的縝密于細(xì)致,其實(shí)這也取決于當(dāng)時(shí)Gosling或其開發(fā)團(tuán)隊(duì)的想法,當(dāng)然作為這么優(yōu)秀的語言,我們確實(shí)應(yīng)該學(xué)習(xí)得更加細(xì)致。臧圩人2008-07-04回復(fù)sooo:你的理解是對(duì)的,最后一例中,a的確沒有被加入字符串池中,而b被加入了。而對(duì)于這句話:

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論