乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       貪挽懶月 2022-06-20 發(fā)布于廣東

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

      一、形參和實參:

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

      1. public static void test(String name){

      2. System.out.println(name);

      3. }

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

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

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

      2. String name = "劉亦菲";

      3. test(name);

      4. }

      這個String name = "劉亦菲"中這個name,在test方法被調(diào)用之前就就已被創(chuàng)建并且初始化,在調(diào)用test方法時,它就被當(dāng)作實際參數(shù)傳入,這就是實參。

      二、Java中的內(nèi)存:

      Java中內(nèi)存分為5片,分別是棧、堆、方法區(qū)、程序計數(shù)器、本地方法棧。

      1、棧:又稱虛擬機棧。特點是先進(jìn)后出。棧的線程是私有的,也就是線程之間的棧是隔離的。棧中有若干棧幀,每個棧幀對應(yīng)一個方法。也就是說,當(dāng)程序開始執(zhí)行一個方法時,就會在棧中創(chuàng)建一個棧幀入棧,方法結(jié)束后,該棧幀出棧??聪旅娴膱D解:每個棧幀主要包括:

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

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

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

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

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

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

      1、基本類型的存儲:

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

      1. int age = 6;

      2. int grade = 6;

      3. int weight = 50;

      先創(chuàng)建一個age變量,存儲在棧幀中的局部變量表,然后查找棧中是否有字面量值為6的內(nèi)容,如果有,直接把age指向這個地址,沒有開辟內(nèi)存空間來存儲"6"這個內(nèi)容,同時讓age指向它。當(dāng)創(chuàng)建grade變量時,因為已經(jīng)有字面量為"6"的內(nèi)容了,所以直接拿過來用。所以棧中的數(shù)據(jù)在當(dāng)前線程下是共享的。上面的代碼在內(nèi)存中的圖解如下:

      如果給age重新賦值:

      1. age = 10;

      難么就會在棧中查找是否有字面量為"10"的內(nèi)容,有就直接拿來用,沒有就開辟內(nèi)存空間存儲"10",然后age指向這個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();

      時分兩個過程:

      1. User user;// 定義變量

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

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

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

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

      • 值傳遞:方法調(diào)用時,實際參數(shù)把它的值的副本傳遞給對應(yīng)的形式參數(shù),此時形參接收到的其實只是實參值的一個拷貝,所以在方法內(nèi)對形參做任何操作都不會影響實參??聪旅嬉欢未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)用后并沒有改變,所以傳入方法的只是實參的拷貝。

      • 引用傳遞:當(dāng)參數(shù)是對象的時候,其實傳遞的對象的地址值,所以實參的地址值傳給形參后,在方法內(nèi)對形參進(jìn)行操作會直接影響真實內(nèi)容。看下面的代碼:定義對象:

      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重新賦值,直接影響這個對象,所以方法執(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了一個user對象x0001,然后調(diào)用userTest方法,userTest方法進(jìn)棧,并且把user對象的地址值x0001傳入userTest方法,所以在userTest方法中對user進(jìn)行操作直接影響地址值為x0001的對象。所以就出現(xiàn)了第一次運行結(jié)果。

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

      1. user = new User();

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

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

        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多