作者:cheerui;
主頁:http://cheerui.cn
Java真的只有值傳遞


JAVA核心技術卷一中說JAVA程序設計語言中是採用按值調用

值傳遞和引用傳遞

值傳遞(pass by value)是指在調用函數時將實際參數複製一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。

引用傳遞(pass by reference)是指在調用函數時將實際參數的地址直接傳遞到函數中,那麼在函數中對參數所進行的修改,將影響到實際參數,形參和實參總是指向同一個地址,形參指向哪裏實參就會指向哪裏。

java中的基本數據類型和引用數據類型

java中的基本數據類型:

  • 4種整數類型:byte、short、int、long
  • 2種浮點數類型:float、double
  • 1種字符類型:char
  • 1種布爾類型:boolean

java中的引用數據類型:

  • 接口
  • 數組
下面就對JAVA中傳遞參數是值傳遞還是引用傳遞展開討論

下面先來看基本數據類型

public class Test {
static void testInt(int a, int b)
{
a=10;
b=20;
System。out。println("交換後 "+"a:"+a+", b:"+b);
}
public static void main(String[] args)
{
int a=1;
int b=2;
System。out。println("交換前 "+"a:"+a+", b:"+b);
testInt(a,b);
System。out。println("方法結束後"+"a:"+a+", b:"+b);
}
}

運行結果是這樣的:


Java真的只有值傳遞


下面的頭文字D的例子中:拓海 在棧中的實參名字,阿樹 在棧中的形參名字 ,鑰匙 指向堆中實例的地址,賽車 堆中的實例,比賽 程序中的方法(update,testInt)

java中基本數據類型在傳遞的時候,用的是值傳遞,就是拷貝和實參一模一樣的值然後由形參進行操作,當方法結束後,形參的生命週期就會終止,實參的值並沒有受到影響。

這裏舉個頭文字D的例子,拓海有一輛AE86,過兩天阿樹有一場比賽,阿樹想借拓海的這輛AE86,在比賽開始前拓海複製了一個一模一樣的AE86給阿樹,阿樹又對這輛複製出來的AE86進行了改裝,比賽結束後,阿樹感覺比賽失利了,就開着車永久消失了。改裝並沒有影響到原來的AE86,這就是值傳遞,形參不會改變實參的值。

下面來看引用數據類型

// 類的編寫
class Car
{
public String name;
public Car()
{}
public Car(String name)
{
this。name=name;
}
}

下面進行測試

public class Test
{
public static void update1(Car car)
{
car。name="GTR";
System。out。println("修改後的名字是:"+car。name);
}
//這個方法比上面的方法多了一條a=new Car()語句
public static void update2(Car car)
{
car=new Car();
car。name="GTR";
System。out。println("修改後的名字是:"+car。name);
}
public static void main(String[] args)
{
Car a=new Car("AE86");
Car b=new Car("AE86");
System。out。println("調用update1前a的名字是:"+a。name);
update1(a);
System。out。println("調用update1後a的名字是:"+a。name);
System。out。println("調用update2前b的名字是:"+b。name);
update2(b);
System。out。println("調用update2後b的名字是:"+b。name);
}
}

運行結果是這樣的:


Java真的只有值傳遞


看完上面的update1方法,覺得引用數據類型和基本數據類型不一樣,引用數據類型傳入方法後,方法調用結束後對象的屬性發生了變化,認爲這是引用傳遞,將對象a的地址送到了形參中,然後對形參改變實參就會改變。

但是update2馬上就推翻了這個想法,將實參送入形參後,形參馬上在堆中新建了一個對象,如果是引用傳遞,那麼此時形參和實參都是指向這個對象的,然後程序又對形參的name屬性進行了修改,那麼此時實參也會被修改,看到的結果就應該和update1一樣。但是結果卻不是這樣的,並沒有修改數據,這就說明了將對象作爲實參傳入方法的形參,並不是引用傳遞。

那麼java中引用類型數據到底是怎麼回事那,下面把自己的查閱資料理解的寫下來。作爲後續回顧。

Car b = new Car(“AE86”);

執行這個語句首先會在棧中創建一個b變量,然後在堆中創建一個Car類的實例,然後b指向堆中的實例。

其實在java程序中,將對象傳入形參中,也是值傳遞,基本數據類型值傳遞就是拷貝一個變量的副本;下面以update2()分析,引用數據類型就是將變量名(b)指向堆的地址複製一份,也就是說在棧中有一個變量名(car)也指向堆中b的實例。

現在執行 car =new car();就是形參car指向了堆中一個新的地址,而b還是指向原來的地址的,這樣的話,car隨便修改name屬性,是影響不到b的。最後方法結束car被釋放,堆中的新對象被GC回收。

在update1()中可以修改是因爲形參和實參指向同一塊內容,當形參修改name屬性,那麼堆中的對象就會被修改,update1()執行結束後,car釋放,但堆中的實例還有變量指向,不會被回收,這時就修改了b的值。

還是用頭文字D的例子來說明

引用傳遞:

還是有比賽,比賽(方法)前,拓海(棧中存的變量名,實參)將AE86(堆中類的實例)鑰匙(地址)交給了阿樹(形參),比賽途中阿樹對AE86進行了改裝,比賽後阿樹消失了,但是鑰匙給了拓海,那麼此時的車是經過改裝的。

Car=new Car();在例子中的體現:

比賽中,阿樹感覺AE86不好開,旁邊有一輛GTR,然後阿樹用手上的這把鑰匙捅開了GTR(new Car();),就開着GTR完成了比賽,AE86在路上找不到了(因爲此時沒有變量指向這輛AE86,會被GC回收),然後比賽完成後,阿樹消失了,但鑰匙給了拓海,此時的車是GTR。

JAVA中引用數據的傳輸

賽前,拓海將鑰匙配了一個交給了阿樹,阿樹在比賽中對車進行了改裝,比賽完之後阿樹和鑰匙一起消失了,那麼拓海用鑰匙開車,車是經過改裝過的。

Car=new Car();在例子中的體現:

比賽中,阿樹感覺AE86不好開,旁邊有一輛GTR,然後阿樹用配的的這把鑰匙捅開了GTR(new Car();),這時候AE86是不會找不到的(因爲此時拓海的鑰匙還是指向這輛車的),阿樹開着GTR完成了比賽,比賽後阿樹和鑰匙消失了,GTR也會消失(沒有鑰匙指向這輛車),此時的車還是AE86。

這兩個是不同的:引用傳遞是真的將地址交給了形參,形參和實參始終指向堆中的一個類的實例;而java中引用類型的傳遞,則是將實參的地址複製一份交給了形參,這就符合值傳遞的概念,複製一個副本,只不過這裏複製的是一個地址罷了。

參考鏈接:

https://mp.weixin.qq.com/s/4efxpvxOAzg1E4eLIsRLiwhttps://juejin.im/entry/5ac187ad6fb9a028e52dfaee
相关文章