Java 中的值傳遞

其實 Java 中是只存在值傳遞的,不存在引用傳遞。因為我們大多數(shù)人是從 C 語言入門,而 C 語言中是存在引用傳遞的,所以很容易在 Java 中混淆。

你還在為開發(fā)中頻繁切換環(huán)境打包而煩惱嗎?快來試試 Environment Switcher 吧!使用它可以在app運行時一鍵切換環(huán)境,而且還支持其他貼心小功能,有了它媽媽再也不用擔心頻繁環(huán)境切換了。https://github.com/CodeXiaoMai/EnvironmentSwitcher

數(shù)據(jù)類型分類

Java 中的數(shù)據(jù)類型分為兩大類:基本類型對象類型,相對應的變量也分為兩類:基本類型引用類型。

// int 基本類型的數(shù)據(jù)類型,num 基本類型的變量,變量的值 10 直接保存在變量 num 中。
int num = 10;
// String 對象類型的數(shù)據(jù)類型,str 引用類型的變量,str 中保存的是 "hello" 在內存中的首地址。
String str = "hello";

下面這張圖代表了變量中保存的值,以及實際對象在內存中的情況。


image

當修改變量的值時:

num = 20;
str = "java";
image

通過上圖可以看出:

  • 對于基本類型的變量 num,賦值運算符會直接改變它的值,原來的值被覆蓋。
  • 對于引用類型的變量 str,賦值運算符會將 str 中保存的內存地址(“hello”的地址)改為新的地址(“java”的地址),原來的地址被覆蓋了,但是原來的地址指向的對象(“hello”)不會改變,只是沒有任何引用指向它,會在垃圾回收機制觸發(fā)時被回收。

參數(shù)傳遞

這里首先要記住一點:參數(shù)傳遞就是賦值操作,也就是說,我們調用一個帶參的函數(shù)時,形參和實參是兩個變量,在內存中也是開辟了兩個空間,只是把實參的值賦值給了形參。這是理解 Java 中只有值傳遞的關鍵。

下面就通過幾個例子證明這一點。

例1.基本類型的變量傳參

基本類型的變量傳參

輸出結果:

99

這個很好理解,其實通過編譯器也可以發(fā)現(xiàn),foo() 方法中的 num 顏色為灰色并且?guī)в胁ɡ司€,把鼠標放到變量上還會看到提示:“Parameter can be converted to a local variable”。意思就是這個變量可以轉化為一個本地變量,也就是在方法內部聲明。根據(jù)“參數(shù)傳遞就是賦值操作”,來梳理一下整個過程。當調用 foo() 方法時,將實參( num) 的值賦值給了形參(num1 ),這時內存中存在兩個變量 num(實參)、num1(形參),因為基本類型的變量賦值是直接覆蓋操作,所以我們對形參(num1)的操作只是改不了形參的值,而不會影響實參(num) 。

例2.普通引用類型的變量傳參

說是普通引用類型,是指類內部提供了改變自身的方法。

普通引用類型的變量傳參

這次可以發(fā)現(xiàn)編譯器沒有提示異常信息,這至少可以證明,在 foo() 方法中對形參 myObject1 進行操作之后,形參 myObject1 仍然被引用,那是不是可以證明形參 myObject1 和實參 myObject 是同一個對象呢?我們先看看結果:

100

結果證明,foo 方法中的實參 myObject 和形參 myObject1 確實是指向同一個對象。再根據(jù)“參數(shù)傳遞就是賦值操作”這句話,來梳理一下。當調用 foo() 方法時,將實參(myObject) 的值(引用對象的內存地址)賦值給形參 (myObject1),這時內存中存在兩個變量 myObject(實參)、myObject1(形參),但是它們都指向同一個內存地址,所以我們對形參(myObject1)的操作會影響實參(myObject) 。

例3.特殊引用類型的變量傳參

上面提到了普通引用類型,當然就存在特殊引用類型了,它是指自身保存的值不可修改。如:String 和 Integer、Double、Boolean 等基本類型的包裝類,它們都是 Immutable 類型的(它們的值都是 final 修飾的),所以每次對它們進行賦值操作,都是創(chuàng)建一個新的對象。

特殊引用類型的變量傳參

我們發(fā)現(xiàn) foo() 方法中的 value 被編譯器提示可修改為本地變量。這就和例 1 中一樣在 foo 方法中對形參的修改不會影響到實參,輸出結果:

hello

這次根據(jù)“參數(shù)傳遞就是賦值操作”以及特殊引用類型的特點來梳理一下。當調用 foo() 方法時,將實參(value) 的值(引用對象的內存地址)賦值給形參 (value1),這時內存中存在兩個變量 value(實參)、value1(形參),而且它們都指向同一個內存地址,但是當我們對形參(value1)進行賦值操作時,因為它是一個自身不可修改的特殊引用類型,所以"hello"對象并沒有修改,而是在內存中又創(chuàng)建了一個值為"java”的新對象,并把“java”的地址賦值給形參,所以只是形參變了,而實參還是指向“hello”對象。

例4. 對普通引用類型使用賦值運算符

這次把 foo() 方法進行了修改,在方法內對形參進行重新賦值操作。

對普通引用類型使用賦值運算符

這時編譯器又提示了形參 myObject 可以修改為本地變量。再根據(jù)“參數(shù)傳遞就是賦值操作”這句話,來梳理一下。當調用 foo() 方法時,將實參(myObject) 的值(引用對象的內存地址)賦值給形參 (myObject1),這時內存中存在兩個變量 myObject(實參)、myObject1(形參),而且它們都指向同一個內存地址,但是在方法內部又對形參進行了一次賦值操作,這時形參指向了一個新的對象,而實參仍然指向原來的對象,這樣形參和實參之間沒有任何關聯(lián)了。所以我們對形參(myObject1)的操作不會影響實參(myObject) 。

其實 foo() 方法等同于:

private static void foo() {
    MyObject myObject = new MyObject();
    myObject.num = 100;
}

同樣可以看出 foo() 方法中的形參和實參完全沒有關系了。

總結

Java 中參數(shù)傳遞其實就是賦值操作。
Java 中只存在值傳遞。

  • 對于基本類型變量,是把實參的值直接復制給形參。
  • 對于引用類型變量,是把實參引用的對象的內存地址復制給形參,所以實參和形參指向同一個對象。
  • 特殊引用類型變量,因為自身不可變的特點,當再次對形參進行賦值操作后,形參指向一個新的對象,而實參扔指向原來的對象。特殊引用類型變量包括 String 和一些基本類型的包裝類(Integer、Double、Boolean等)。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 引言 學習過C語言的同學都很清楚在c中調用方法的參數(shù)有值傳遞和引用傳遞兩種方式。關于值傳遞和引用傳遞網(wǎng)上有許多的博...
    寧愿呢閱讀 1,474評論 0 4
  • 方法調用是編程語言中非常重要的一個特性,在方法調用時,通常需要傳遞一些參數(shù)來完成特定功能。 我們首先觀察一個簡單的...
    小人物灌籃閱讀 597評論 0 0
  • 本文首發(fā)于我的個人博客 —— Bridge for You,轉載請標明出處。 前言 在開始看我畫小狗之前,咱們先來...
    柳樹之閱讀 1,232評論 5 19
  • 今天復習Java基礎,發(fā)現(xiàn)有一個概念好像有點模糊了,就是值傳遞,Think in Java中說Java只有值傳遞。...
    莫那一魯?shù)?/span>閱讀 682評論 0 4
  • 昨天有點戲劇化,忘了寫了…是的,下班后同事沒帶鑰匙!進不去家,也進不了公司…沒辦法只能在外面訂了了酒店…這個厲害了
    滴滴動力閱讀 270評論 0 0

友情鏈接更多精彩內容