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

Createsequence發表於2020-08-05

一、概述

曾經糾結了很久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.共享物件傳遞的特點:

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

相關文章