Java參數傳遞是值傳遞仍是引用傳遞?

當一個對象被看成參數傳遞到一個方法後,在此方法內能夠改變這個對象的屬性,那麼這裏究竟是值傳遞仍是引用傳遞?ide

答:是值傳遞。Java 語言的參數傳遞只有值傳遞。當一個實例對象做爲參數被傳遞到方法中時,參數的值就是該對象的引用的一個副本。指向同一個對象,對象的內容能夠在被調用的方法內改變,但對象的引用(不是引用的副本) 是永遠不會改變的。函數

 

 

Java的參數傳遞,無論是基本數據類型仍是引用類型的參數,都是按值傳遞,沒有按引用傳遞!this

 咱們能夠看一下microsoft的文檔中對按引用傳遞參數的定義(以下截圖):https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference  spa

 

對於參數的傳遞能夠分爲兩種狀況:3d

1.基本數據類型的參數code

 1 public class TransferTest {
 2     public static void main(String[] args) {
 3         int num = 1;
 4         System.out.println("changeNum()方法調用以前:num = " + num);
 5         changeNum(num);
 6         System.out.println("changeNum()方法調用以後:num = " + num);
 7     }
 8 
 9     public static void changeNum(int x) {
10         x = 2;
11     }
12 }

運行結果:對象

傳遞過程的示意圖以下:blog

分析:num做爲參數傳遞給changeNum()方法時,是將內存空間中num所指向的那個存儲單元中存放的值1複製了一份傳遞給了changeNum()方法中的x變量,而這個x變量也在內存空間中分配的一個存儲單元。這時就把num對的值1傳遞給了x變量所指向的存儲單元中。此後在changeNum()方法中對x變量的一切操做都是針對於x所指向的這個存儲單元,與num所指向的存儲單元無關。內存

 

因此,在changeNum()方法被調用後,num所指向的存儲單元的值仍是沒有發生變化,這就是所謂的「值傳遞」。文檔

值傳遞的精髓是:傳遞的是存儲單元中的內容,而不是存儲單元的引用。

 

2.引用類型的參數

示例1:

 1  public class TransferTest2 {
 2     public static void main(String[] args) {
 3         Person person = new Person();
 4         System.out.println(person);
 5         change(person);
 6         System.out.println(person);
 7     }
 8 
 9     public static void change(Person p) {
10         p = new Person();
11     }
12 }
13 
14 /**
15  * Person類
16  */
17 class Person {
18 
19 }

 

 運行結果:

能夠看出兩次打印結果一致。即調用change()方法後,person變量並沒發生改變。

 

傳遞過程的示意圖以下:

分析:

01.當程序執行到第3行 Person person = new Person()時,程序在堆內存(heap)中開闢了一塊內存空間用來存儲Person類實例對象,同時在棧內存(stack)中開闢了一個存儲單元來存儲該實例對象的引用,即上圖中person指向的存儲單元。

02.當程序執行到第5行 change(person)時,person做爲參數(實參)傳遞給餓了change()方法。這裏是person將本身的存儲單元的內容傳遞給了change()方法的p變量。此後在change()方法中對p變量的一切操做都是針對於p變量所指向的存儲單元,與perosn所指向的存儲單元就沒有關係了。

 

示例2:

 1 public class P {
 2     String name = "P";
 3     public P(String name) {
 4         this.name = name;
 5     }
 6     @Override
 7     public String toString() {
 8         return name;
 9     }
10 }
11 
12 public class Test {
13     static P p1 = new P("p1");
14     public static void main(String[] args) {
15         P p = new P("P");
16      System.out.println("before change p:" + p.toString);
17         changeObj(p);
18         System.out.println("after change p:" + p.toString());
19     }
20 
21     static void changeObj(P p) {
22         p = new P("pp");
23         System.out.println("change p:" + p.toString());
24         //p = p1;
25         //System.out.println(p.toString());
26     }
27 }

運行結果:

首先要理解 「=」 賦值操做的意義:

對於基本數據類型來講 「=」賦值操做是直接改變內存地址(存儲單元)上的值。

對於引用類型來講 「=」 賦值操做是改變引用變量所指向的內存地址(上文中存儲單元)。

調用changeObj()方法進入第21行:

 

 

 執行22行後:

因此對外部的p變量是沒有影響的。

總結:

函數參數傳遞實際上是一個賦值的過程,基本類型傳遞的是數值,引用類型傳遞的引用對象的內存地址。

另一點要特別注意,函數的參數實際上是函數內部的局部變量。不要跟外部變量混淆。

 

 

示例3:

 1 package cn.canshu;
 2 class Person{
 3     private int id;
 4     private String name;
 5     public Person(int id,String name) {
 6         this.id = id;
 7         this.name = name;
 8     }
 9 }
10 public class Demo02 {
11     public static void main(String[] args) {
12         Person a = new Person(23, "a");
13         Person b = new Person(22,"b");
14         System.out.println("交換前\na:"+a+"\nb:"+b);
15         swap(a, b);
16         System.out.println("交換後\na:"+a+"\nb:"+b);
17     }
18     private static void swap(Person a, Person b) {
19         Person temp = a;
20         a = b;
21         b = temp;
22     }
23 }

運行結果:

同理,外部的ab引用不是內部的ad引用,故不會發生改變。

咱們能夠發現,Java方法的傳值,其實是把實參的值—-對象引用(對象的內存地址)傳遞給了形參,從而形參和實參的值(即變量裏存儲的內存地址,非變量自己的內存地址)是相同的,指向了同一個對象/內存地址。

相關文章
相關標籤/搜索