|
可能很多人都知道java中參數(shù)有形參和實(shí)參之分,卻不知道區(qū)別到底是什么;知道Java中內(nèi)存分為棧、堆、方法區(qū)等5片內(nèi)存,不知道每片內(nèi)存中保存的都是什么;關(guān)于參數(shù)的傳遞到底是值傳遞還是引用傳遞傻傻分不清楚。本文將為你逐一揭秘! 一、形參和實(shí)參:
test方法中的參數(shù)name就是形參,只有在test方法在被調(diào)用這個(gè)name的生命周期才開始,才會(huì)分配內(nèi)存空間,當(dāng)test方法調(diào)用完后,這個(gè)name也就不復(fù)存在。
這個(gè)String name = "劉亦菲"中這個(gè)name,在test方法被調(diào)用之前就就已被創(chuàng)建并且初始化,在調(diào)用test方法時(shí),它就被當(dāng)作實(shí)際參數(shù)傳入,這就是實(shí)參。 二、Java中的內(nèi)存:Java中內(nèi)存分為5片,分別是棧、堆、方法區(qū)、程序計(jì)數(shù)器、本地方法棧。 1、棧:又稱虛擬機(jī)棧。特點(diǎn)是先進(jìn)后出。棧的線程是私有的,也就是線程之間的棧是隔離的。棧中有若干棧幀,每個(gè)棧幀對應(yīng)一個(gè)方法。也就是說,當(dāng)程序開始執(zhí)行一個(gè)方法時(shí),就會(huì)在棧中創(chuàng)建一個(gè)棧幀入棧,方法結(jié)束后,該棧幀出棧??聪旅娴膱D解:
2、堆:堆內(nèi)存用來存儲(chǔ)對象和數(shù)組。數(shù)組以及所有new出來的對象都存儲(chǔ)在堆內(nèi)存中。在JVM中只有一個(gè)堆,所以堆是被所有線程共享的。 3、方法區(qū):方法區(qū)也是所有線程共享的區(qū)域,主要存儲(chǔ)靜態(tài)變量、常量池等。 三、數(shù)據(jù)在內(nèi)存中的存儲(chǔ):1、基本類型的存儲(chǔ):
先創(chuàng)建一個(gè)age變量,存儲(chǔ)在棧幀中的局部變量表,然后查找棧中是否有字面量值為6的內(nèi)容,如果有,直接把a(bǔ)ge指向這個(gè)地址,沒有開辟內(nèi)存空間來存儲(chǔ)"6"這個(gè)內(nèi)容,同時(shí)讓age指向它。當(dāng)創(chuàng)建grade變量時(shí),因?yàn)橐呀?jīng)有字面量為"6"的內(nèi)容了,所以直接拿過來用。所以棧中的數(shù)據(jù)在當(dāng)前線程下是共享的。上面的代碼在內(nèi)存中的圖解如下: 如果給age重新賦值:
難么就會(huì)在棧中查找是否有字面量為"10"的內(nèi)容,有就直接拿來用,沒有就開辟內(nèi)存空間存儲(chǔ)"10",然后age指向這個(gè)10。所以基本類型的變量,變量值本身是不會(huì)改變的,重新賦值后,只是指向了新的引用而已。
調(diào)用:
在內(nèi)存中的存儲(chǔ)圖解:
2、引用類型的存儲(chǔ):通過上圖可以發(fā)現(xiàn),執(zhí)行
時(shí)分兩個(gè)過程:
定義變量時(shí),會(huì)在棧中開辟內(nèi)存空間存放user變量;賦值時(shí)會(huì)在堆內(nèi)存中開辟內(nèi)存空間存儲(chǔ)User實(shí)例,這個(gè)實(shí)例會(huì)有一個(gè)地址值,同時(shí)把這地址值賦給棧中的user變量。所以引用類型的變量名存儲(chǔ)在棧中,變量值存儲(chǔ)的是堆中相對應(yīng)的地址值,并不是存儲(chǔ)的實(shí)際內(nèi)容。 四、參數(shù)傳遞問題:關(guān)于參數(shù)的傳遞,可能有點(diǎn)難理解,到底是值傳遞還是引用傳遞?下面一起來學(xué)習(xí)一下:
執(zhí)行結(jié)果如下: 從結(jié)果可以發(fā)現(xiàn),name和age在方法調(diào)用后并沒有改變,所以傳入方法的只是實(shí)參的拷貝。
測試:
結(jié)果如下:
可以看到在方法內(nèi)對user重新賦值,直接影響這個(gè)對象,所以方法執(zhí)行完畢后輸出的是修改后的user。 對上面的測試方法稍作修改:
執(zhí)行結(jié)果如下:
結(jié)果卻是,方法執(zhí)行后的user竟然沒改變。 分析一下這兩次的執(zhí)行過程:第一次: 第一次執(zhí)行過程如上圖,main方法進(jìn)棧后,在堆中new了一個(gè)user對象x0001,然后調(diào)用userTest方法,userTest方法進(jìn)棧,并且把user對象的地址值x0001傳入userTest方法,所以在userTest方法中對user進(jìn)行操作直接影響地址值為x0001的對象。所以就出現(xiàn)了第一次運(yùn)行結(jié)果。 第二次:
到了這里,又在堆中new了一個(gè)user對象x0002,然后讓棧中user變量指向新的user對象的地址值x0002。所以接下來在方法中對user的操作都是對地址值為x0002的對象的操作,自然不會(huì)影響到地址值為x0001的對象。所以就出現(xiàn)了第二次的運(yùn)行結(jié)果。 小結(jié):由上面的案例可以得出結(jié)論,基本類型傳的是值的副本,引用類型傳的是地址值,所以不論傳的是引用類型還是基本類型,其實(shí)都是值傳遞。 |
|
|