免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
一文讓你明白值傳遞和引用傳遞

可能很多人都知道java中參數(shù)有形參和實(shí)參之分,卻不知道區(qū)別到底是什么;知道Java中內(nèi)存分為棧、堆、方法區(qū)等5片內(nèi)存,不知道每片內(nèi)存中保存的都是什么;關(guān)于參數(shù)的傳遞到底是值傳遞還是引用傳遞傻傻分不清楚。本文將為你逐一揭秘!

一、形參和實(shí)參:

  • 形參:就是定義方法時(shí),該方法攜帶的參數(shù)。比如定義如下方法:

  1. public static void test(String name){

  2. System.out.println(name);

  3. }

test方法中的參數(shù)name就是形參,只有在test方法在被調(diào)用這個(gè)name的生命周期才開始,才會分配內(nèi)存空間,當(dāng)test方法調(diào)用完后,這個(gè)name也就不復(fù)存在。

  • 實(shí)參:方法在被調(diào)用時(shí)實(shí)際傳入的參數(shù)值,實(shí)參在方法調(diào)用前就已經(jīng)被初始化。例子:

  1. public static void main(String[] args){

  2. String name = "劉亦菲";

  3. test(name);

  4. }

這個(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í),就會在棧中創(chuàng)建一個(gè)棧幀入棧,方法結(jié)束后,該棧幀出棧??聪旅娴膱D解:

每個(gè)棧幀主要包括:

  • 局部變量表:存儲方法中的局部變量。當(dāng)局部變量是基本類型時(shí),存儲的是變量的值;當(dāng)變量是引用類型時(shí),存儲的是地址值。

  • 運(yùn)行時(shí)常量池的引用:存儲程序執(zhí)行時(shí)可能會用到的常量的引用。

  • 方法返回地址:存儲方法執(zhí)行完成后的返回地址。

2、堆:堆內(nèi)存用來存儲對象和數(shù)組。數(shù)組以及所有new出來的對象都存儲在堆內(nèi)存中。在JVM中只有一個(gè)堆,所以堆是被所有線程共享的。

3、方法區(qū):方法區(qū)也是所有線程共享的區(qū)域,主要存儲靜態(tài)變量、常量池等。

三、數(shù)據(jù)在內(nèi)存中的存儲:

1、基本類型的存儲:

  • 基本類型的局部變量:變量以及數(shù)值都是存儲在棧內(nèi)存中。比如在某個(gè)方法中定義有如下局部變量:

  1. int age = 6;

  2. int grade = 6;

  3. int weight = 50;

先創(chuàng)建一個(gè)age變量,存儲在棧幀中的局部變量表,然后查找棧中是否有字面量值為6的內(nèi)容,如果有,直接把a(bǔ)ge指向這個(gè)地址,沒有開辟內(nèi)存空間來存儲"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重新賦值:

  1. age = 10;

難么就會在棧中查找是否有字面量為"10"的內(nèi)容,有就直接拿來用,沒有就開辟內(nèi)存空間存儲"10",然后age指向這個(gè)10。所以基本類型的變量,變量值本身是不會改變的,重新賦值后,只是指向了新的引用而已。

  • 基本類型的成員變量:基本類型的成員變量的變量名和值都是存儲在堆內(nèi)存中的,其生命周期和對象是一致的??聪旅娴拇a:

  1. public class User{

  2. private int age;

  3. private String name;

  4. private int grade;

  5. ......

  6. }

調(diào)用:

  1. User user = new User();

在內(nèi)存中的存儲圖解:

  • 基本類型的靜態(tài)變量:基本類型的靜態(tài)變量存儲于方法區(qū)的常量池中,隨著類的加載而加載。

2、引用類型的存儲:通過上圖可以發(fā)現(xiàn),執(zhí)行

  1. User user = new User();

時(shí)分兩個(gè)過程:

  1. User user;// 定義變量

  2. user = new User();// 賦值

定義變量時(shí),會在棧中開辟內(nèi)存空間存放user變量;賦值時(shí)會在堆內(nèi)存中開辟內(nèi)存空間存儲User實(shí)例,這個(gè)實(shí)例會有一個(gè)地址值,同時(shí)把這地址值賦給棧中的user變量。所以引用類型的變量名存儲在棧中,變量值存儲的是堆中相對應(yīng)的地址值,并不是存儲的實(shí)際內(nèi)容。

四、參數(shù)傳遞問題:

關(guān)于參數(shù)的傳遞,可能有點(diǎn)難理解,到底是值傳遞還是引用傳遞?下面一起來學(xué)習(xí)一下:

  • 值傳遞:方法調(diào)用時(shí),實(shí)際參數(shù)把它的值的副本傳遞給對應(yīng)的形式參數(shù),此時(shí)形參接收到的其實(shí)只是實(shí)參值的一個(gè)拷貝,所以在方法內(nèi)對形參做任何操作都不會影響實(shí)參??聪旅嬉欢未a:

  1. public class Test {

  2. public static void test(int age,String name){

  3. System.out.println("傳入的name:"+name);

  4. System.out.println("傳入的age:"+age);

  5. age = 66;

  6. name = "張馨予";

  7. System.out.println("方法內(nèi)重新賦值的name:"+name);

  8. System.out.println("方法內(nèi)重新賦值的age:"+age);

  9. }

  10. public static void main(String[] args){

  11. String name = "劉亦菲";

  12. int age = 44;

  13. test(age,name);//調(diào)用方法

  14. System.out.println("方法執(zhí)行后的name:"+name);

  15. System.out.println("方法執(zhí)行后的age:"+age);

  16. }

  17. }

       執(zhí)行結(jié)果如下:

從結(jié)果可以發(fā)現(xiàn),name和age在方法調(diào)用后并沒有改變,所以傳入方法的只是實(shí)參的拷貝。

  • 引用傳遞:當(dāng)參數(shù)是對象的時(shí)候,其實(shí)傳遞的對象的地址值,所以實(shí)參的地址值傳給形參后,在方法內(nèi)對形參進(jìn)行操作會直接影響真實(shí)內(nèi)容??聪旅娴拇a:定義對象:

  1. @Data

  2. public class User {

  3. private String name;

  4. private int age;

  5. }

     測試:

  1. public class Test {

  2. public static void userTest(User user){

  3. System.out.println("傳入的user:"+user);

  4. user.setName("張馨予");

  5. user.setAge(20);

  6. System.out.println("方法內(nèi)重新賦值的user:"+user);

  7. }

  8. public static void main(String[] args){

  9. User user = new User();

  10. user.setName("劉亦菲");

  11. user.setAge(18);

  12. userTest(user);//調(diào)用方法

  13. System.out.println("方法執(zhí)行后的user:"+user);

  14. }

  15. }

      結(jié)果如下:

可以看到在方法內(nèi)對user重新賦值,直接影響這個(gè)對象,所以方法執(zhí)行完畢后輸出的是修改后的user。

對上面的測試方法稍作修改:

  1. public class Test {

  2. public static void userTest(User user){

  3. System.out.println("傳入的user:"+user);

  4. user = new User();//新增這行代碼

  5. user.setName("張馨予");

  6. user.setAge(20);

  7. System.out.println("方法內(nèi)重新賦值的user:"+user);

  8. }

  9. public static void main(String[] args){

  10. User user = new User();

  11. user.setName("劉亦菲");

  12. user.setAge(18);

  13. userTest(user);//調(diào)用方法

  14. System.out.println("方法執(zhí)行后的user:"+user);

  15. }

  16. }

      執(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é)果。

第二次:

第二次執(zhí)行過程如上圖,main方法進(jìn)棧后,在堆中new了一個(gè)user對象x0001,然后調(diào)用userTest方法,userTest方法進(jìn)棧,并且把user對象的地址值x0001傳入userTest方法,在此之前都是和第一次一樣的。接下來在該方法中有

  1. user = new User();

到了這里,又在堆中new了一個(gè)user對象x0002,然后讓棧中user變量指向新的user對象的地址值x0002。所以接下來在方法中對user的操作都是對地址值為x0002的對象的操作,自然不會影響到地址值為x0001的對象。所以就出現(xiàn)了第二次的運(yùn)行結(jié)果。

小結(jié):由上面的案例可以得出結(jié)論,基本類型傳的是值的副本,引用類型傳的是地址值,所以不論傳的是引用類型還是基本類型,其實(shí)都是值傳遞。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Java程序內(nèi)存的簡單分析
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服