中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java:關(guān)于值傳遞你需要了解的事情

2018-07-02    來源:importnew

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

我們都知道,在Java中,方法的參數(shù)傳遞永遠(yuǎn)都是指值傳遞。讓我們來看一看基本類型和集合的參數(shù)傳遞在內(nèi)存中是如何體現(xiàn)的。

原文鏈接:https://dzone.com/articles/java-pass-by-reference-or-pass-by-value

在討論Java中參數(shù)是如何傳遞之前,我們有必要先弄清楚Java的變量(主要指的是基本類型和對象)是怎么存儲在內(nèi)存中的。
基本類型一般都存儲在堆棧中;對于Java對象,實際的對象數(shù)據(jù)存儲在堆中,而對象的指針(指向推中的對象)存儲在堆棧中。

 

1.png

1.傳值 vs 傳引用

“傳值”和“傳引用”分別是什么意思:

  • 傳值:當(dāng)方法參數(shù)是值傳遞時,意味著原參數(shù)的一個拷貝被傳到了參數(shù)內(nèi)部而不是原始參數(shù),所以任何對于該參數(shù)的改變都只會影響這個拷貝值。
  • 傳引用:當(dāng)方法參數(shù)是引用傳遞時,意味著原始參數(shù)的引用或者說指針被傳遞到了方法內(nèi)部,而不是這個原始參數(shù)的內(nèi)容。

2.在Java中參數(shù)是怎么傳遞的

在Java中,不管原始參數(shù)的類型是什么,參數(shù)都是按值傳遞的。每次當(dāng)一個方法被執(zhí)行的時候,在堆棧中就會為每個參數(shù)創(chuàng)建一個拷貝,這個拷貝會被傳遞到方法內(nèi)部。

  • 如果原始參數(shù)是基本類型,那么在堆棧中創(chuàng)建的便是這個參數(shù)的簡單拷貝
  • 如果原始參數(shù)不是基本類型,那么在堆棧中創(chuàng)建的便是指向真正對象數(shù)據(jù)的新的引用或指針。這個新的引用被傳遞到方法內(nèi)部(在這種情況下,有2個引用指向了同一個對象數(shù)據(jù))

3.解決疑惑

在接下來的示例中,我們通過往方法中傳遞不同類型的參數(shù)(基本類型,包裝類,集合類,自定義類),在方法執(zhí)行完成后去檢查他們是否被修改了來嘗試證明“在Java中參數(shù)傳遞永遠(yuǎn)是值傳遞”。

基本類型參數(shù)

public static void main(String[] args) {
    int x = 1;
    int y = 2;
    System.out.print("Values of x & y before primitive modification: ");
    System.out.println(" x = " + x + " ; y = " + y );
    modifyPrimitiveTypes(x,y);
    System.out.print("Values of x & y after primitive modification: ");
    System.out.println(" x = " + x + " ; y = " + y );
}
private static void modifyPrimitiveTypes(int x, int y)
{
    x = 5;
    y = 10;
}

輸出:

Values of x & y before primitive modification:  x = 1 ; y = 2
Values of x & y after primitive modification:  x = 1 ; y = 2

說明:
x,y這2個參數(shù)是基本類型,所以存儲在堆棧中。當(dāng)調(diào)用modifyPrimitiveTypes()方法時,在堆棧中創(chuàng)建了這2個參數(shù)的拷貝(我們就叫它們w,z),實際上是w,z被傳遞到了方法中。所以原始的參數(shù)并沒有被傳遞到方法中,在方法中的任何修改都只作用于參數(shù)的拷貝w,z

2.png

 

包裝類

public static void main(String[] args) {
    Integer obj1 = new Integer(1);
    Integer obj2 = new Integer(2);
    System.out.print("Values of obj1 & obj2 before wrapper modification: ");
    System.out.println("obj1 = " + obj1.intValue() + " ; obj2 = " + obj2.intValue());
    modifyWrappers(obj1, obj2);
    System.out.print("Values of obj1 & obj2 after wrapper modification: ");
    System.out.println("obj1 = " + obj1.intValue() + " ; obj2 = " + obj2.intValue());
}
private static void modifyWrappers(Integer x, Integer y)
{
    x = new Integer(5);
    y = new Integer(10);
}

輸出:

Values of obj1 & obj2 before wrapper modification: obj1 = 1 ; obj2 = 2
Values of obj1 & obj2 after wrapper modification: obj1 = 1 ; obj2 = 2

說明:
包裝類存儲在堆中,在堆棧中有一個指向它的引用
當(dāng)調(diào)用modifyWrappers()方法時,在堆棧中為每個引用創(chuàng)建了一個拷貝,這些拷貝被傳遞到了方法里。任何在方法里面的修改都只是改變了引用的拷貝,而不是原始的引用

3.png

 

P.S: 如果方法中的表達(dá)式為x += 2,x值得改變也不會影響到方法外部,因為包裝類是immutable類型的。當(dāng)他們的state變化時,他們就會創(chuàng)建一個新的實例。如果你想了解更多關(guān)于immutable類,可以閱讀How to create an immutable class in Java。字符串類型和包裝類相似,所以以上的規(guī)則對于字符串也有效。

集合類型

public static void main(String[] args) {
    List<Integer> lstNums = new ArrayList<Integer>();
    lstNums.add(1);
    System.out.println("Size of list before List modification = " + lstNums.size());
    modifyList(lstNums);
    System.out.println("Size of list after List modification = " + lstNums.size());
}
private static void modifyList(List<Integer> lstParam)
{
    lstParam.add(2);
}

輸出:

Size of list before List modification = 1
Size of list after List modification = 2

說明:
當(dāng)我們創(chuàng)建一個ArrayList或任意集合,在堆棧中便會創(chuàng)建一個指向堆中多個對象的引用。當(dāng)modifyList()被調(diào)用時,一個引用的拷貝被創(chuàng)建中傳遞到了方法中,F(xiàn)在有2個引用指向了真正的對象數(shù)據(jù),其中任何一個引用的數(shù)據(jù)改變會影響到另一個。
在方法中,當(dāng)我們調(diào)用lstParam.add(2)時,一個Integer對象在堆中被創(chuàng)建,添加到了現(xiàn)有的list對象。所以原始的list引用可以看見這次修改,因為2個引用都指向了內(nèi)存中的同一個對象

 

4.png

 

自定義對象

public static void main(String[] args) {
    Student student = new Student();
    System.out.println("Value of name before Student modification = " + student.getName());
    modifyStudent(student);
    System.out.println("Value of name after Student modification = " + student.getName());
}
private static void modifyStudent(Student student)
{
    student.setName("Alex");
}

輸出:

Value of name before Student modification = null
Value of name after Student modification = Alex

說明:
student對象在堆中被創(chuàng)建,在堆棧中存儲著指向它的引用。當(dāng)調(diào)用calling modifyStudent(),在堆棧中創(chuàng)建了這個引用的拷貝,傳遞到了方法中。所以任何對這個對象屬性的修改會影響原始的對象引用

結(jié)論

在Java中,參數(shù)都是按值傳遞的。被傳遞到方法中的拷貝值,要不就是一個引用或一個變量,取決于原始參數(shù)的類型。從現(xiàn)在開始,下面的幾條規(guī)則將幫助你理解方法中對于參數(shù)的修改怎么影響原始參數(shù)變量。

  1. 在方法中,修改一個基礎(chǔ)類型的參數(shù)永遠(yuǎn)不會影響原始參數(shù)值。
  2. 在方法中,改變一個對象參數(shù)的引用永遠(yuǎn)不會影響到原始引用。然而,它會在堆中創(chuàng)建了一個全新的對象。(譯者注:指的是包裝類和immutable對象)
  3. 在方法中,修改一個對象的屬性會影響原始對象參數(shù)。
  4. 在方法中,修改集合和Maps會影響原始集合參數(shù)。

標(biāo)簽:

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:JAVA 同步實現(xiàn)原理

下一篇:深入Spring Boot:快速集成Dubbo + Hystrix