轉(zhuǎn)自 :http://blog.csdn.net/zhaolewen/article/details/6718934 首先理解幾個(gè)概念: 棧:存放基本類型的變量數(shù)據(jù)和對(duì)象的引用,,但對(duì)象本身不存放在棧中,而是存放在堆(new 出來的對(duì)象)或者常量池中(字符串常量對(duì)象存放在常量池中,。) 當(dāng)在一段代碼塊定義一個(gè)變量時(shí),,Java就在棧中為這個(gè)變量分配內(nèi)存空間,當(dāng)超過變量的作用域后,,Java會(huì)自動(dòng)釋放掉為該變量所分配的內(nèi)存空間,,該內(nèi)存空間可以立即被另作他用。 堆:存放所有new出來的對(duì)象,。在堆中分配的內(nèi)存,,由Java虛擬機(jī)的自動(dòng)垃圾回收器來管理。 常量池:在堆中分配出來的一塊存儲(chǔ)區(qū)域,,存放字符串常量和基本類型常量(public static final) 對(duì)于字符串:其對(duì)象的引用都是存儲(chǔ)在棧中的,,如果是編譯期已經(jīng)創(chuàng)建好(直接用雙引號(hào)定義的)的就存儲(chǔ)在常量池中,如果是運(yùn)行期(new出來的)才能確定的就存儲(chǔ)在堆中,。對(duì)于equals相等的字符串,,在常量池中永遠(yuǎn)只有一份,在堆中有多份 大家先來看看下面這段程序: public class Test{ public static void main(String args[]) { String str1 = 'abc'; String str2 = 'abc; String str3 = new String('abc');
System.out.println(str1 == str3); System.out.println(str1.equals(str3)); System.out.println(str2 == str1); } } 這段代碼的運(yùn)行結(jié)果是: println輸出的是false;而第二句則輸出為true,;但是第三句卻是true,。 str1,str2是棧內(nèi)變量,它的內(nèi)存保存的是常量池的常量字符串對(duì)象對(duì)象'abc'的地址 str3是棧內(nèi)變量,,它的內(nèi)存保存的是堆中的new String對(duì)象的地址,,new String在堆中生成對(duì)象,并用常量池的字符串對(duì)象'abc'初始化堆中的對(duì)象,,所以堆中的對(duì)象的內(nèi)存的內(nèi)容和常量池對(duì)象的內(nèi)存的內(nèi)容一樣,,但是是不同的兩個(gè)對(duì)象
在這里很多人會(huì)誤認(rèn)為第一句應(yīng)該是true的,但是事實(shí)卻是false,。這是因?yàn)榈谝痪湓谶M(jìn)行“==”比較的時(shí)候比較的是兩個(gè)指向,,而不是具體指向的內(nèi)容。而第三句在進(jìn)行“==”比較的時(shí)候同樣比較的是指向,,但是他們的指向是相同的,。這種現(xiàn)象出現(xiàn)的原因和字符串在內(nèi)存中實(shí)例化的時(shí)候有關(guān)。 具體情況如下圖所示:
當(dāng)執(zhí)行第一句Str1 = 'abc' 實(shí)例化出第一個(gè)指向,;當(dāng)進(jìn)行第二句Str2 = 'abc' 的時(shí)候出現(xiàn)第二個(gè)指向,,因?yàn)槎褍?nèi)存中存在'abc',而且str2也沒有new一個(gè)新的對(duì)象,,所以為了節(jié)省內(nèi)存,,str2指向了str1所指向的對(duì)象;但是第三句的時(shí)候出現(xiàn)new語句,,他實(shí)例化出了一塊新的空間用來盛放'abc',,自然str3的指向也也是指向這段新開辟的空間。
|