解惑4:java是值傳遞還是引用傳遞

一、概述

曾經糾結了很久java的參數傳遞方式是什麼樣的,後面粗略的了解了一鱗半爪以後有了大概的印象:「傳參數就是值傳遞,傳對象就是引用傳遞」,後面進一步查找了相關資料和文章以後,發現這麼理解是不正確的。

這裡先放結論:

  • java中參數的傳遞可以理解為都是值傳遞
  • 基礎數據類型傳遞的是值的拷貝
  • 對象類型是共享對象傳遞,傳遞的是地址的拷貝

二、形參和實參

要理解參數的傳遞就必須先理解形參和實參:

  • 形參:就是形式參數,用於定義方法的時候使用的參數,是用來接收調用者傳遞的參數的。

    形參只有在方法被調用的時候,虛擬機才會分配記憶體單元,在方法調用結束之後便會釋放所分配的記憶體單元。

    因此,形參只在方法內部有效,所以針對引用對象的改動也無法影響到方法外。

  • 實參:就是實際參數,用於調用時傳遞給方法的參數

舉個例子:

public static void main( String[] args ) {
    String string = "Hello";
    //string是實際參數
    sout(string);
}

public static void sout(String str){
    //str為形式參數
    System.out.println(str);
}

三、值傳遞和引用傳遞與共享對象傳遞

1.值傳遞和引用傳遞

理解了實參和形參,以及java對應的數據類型,我們就可以理解值傳遞和引用傳遞了。

  • 值傳遞:方法調用時,實際參數的被傳遞給對應的形式參數,函數接收的是原始值的一個copy, 此時記憶體中存在兩個相等的基本類型,即實際參數和形式參數,後面方法中的操作都是對形參這個值的修改,不影響實際參數的值

  • 引用傳遞/址傳遞:方法調用時,實際參數的地址被傳遞給方法中相對應的形式參數,函數接收的是原始值的記憶體地址。在方法執行中,形參和實參內容相同,指向同一塊記憶體地址,方法執行中對引用的操作將會影響到實際對象

對於這兩種方式,網上有一個非常形象的圖:

2.共享對象傳遞

但是java的傳值策略有點類似於兩者的結合,是共享對象傳遞

  • 共享對象傳遞:先獲取到實際參數的地址,然後將其複製,並把該地址的拷貝傳遞給被調函數的形式參數。因為參數的地址都指向同一個對象,所以我們稱也之為”傳共享對象”,所以,如果在被調函數中改變了形式參數的值,調用者是可以看到這種變化的。

這也是之所以說java也是值傳遞的原因,共享對象傳遞實際上也是對實參進行拷貝然後賦給形參,但是操作針對的對象不是值而是地址

由於傳遞的是地址的拷貝,所以如果你在方法中將這個地址指向了新的對象,實際上是沒有任何對方法外是沒有任何作用的,舉個例子:

public static void main( String[] args ) {
    Person p = new Person();
    System.out.println("main中:" + p.hashCode());
    change(p);
    System.out.println("main中:" + p.hashCode());
}

public static void change(Person person){
    person = new Person();
    System.out.println("change中:" + person.hashCode());
}

//輸出
main中:692404036
change中:1554874502
main中:692404036

可以看到在main方法中輸出的hashCode指向的都是同一個對象,而change中指向了另一個,可以這麼理解:

  • p為指向了第一個Person對象的地址
  • 把p拷貝了一份得到p『,這裡的p』就是change方法中的形參p
  • change中p指向了一個新的Person對象,在change這個函數範圍里p指向的就是new出來的第二個Person對象的地址
  • 由於change中的p實際上是main中p的拷貝p『,所以在change里p’指向的改變對main中的p不會有任何影響

四、總結

你在福建有座倉庫,給自己配了一把鑰匙

1.三種傳遞:

  • 值傳遞:你建了一座一模一樣的倉庫給別人
  • 引用傳遞:把你家倉庫的鑰匙給了別人
  • 共享對象傳遞:把你家倉庫鑰匙復刻了一把給別人

2.共享對象傳遞的特點:

  • 拷貝的地址與原地址指向同一個記憶體對象:別人用你復刻的鑰匙一樣能進出你的倉庫
  • 拷貝地址引用對象的改變不影響原地址的引用對象:別人在山東也蓋了個倉庫,用你給他的鑰匙配了鎖,他的鑰匙在山東只能開他的倉庫,你的鑰匙在福建只能開你的倉庫