首頁 >常見問題 >java是值傳遞還是引用傳遞

java是值傳遞還是引用傳遞

WBOY
WBOY原創
2022-09-08 14:47:0914336瀏覽

java是值傳遞;值傳遞是指在呼叫方法時將實際參數拷貝一份傳遞到方法中,這樣在方法中如果對參數進行修改,將不會影響到實際參數;當傳的是基本型別時,傳的是值的拷貝,對拷貝變數的修改不影響原變數;當傳的是引用型別時,傳的是引用位址的拷貝,但是拷貝的位址和真實位址指向的都是同一個真實數據,因此可以修改原變數中的值。

java是值傳遞還是引用傳遞

本教學操作環境:windows10系統、DELL G3電腦。

java是值傳遞還是參考傳遞

Java是值傳遞。

當傳的是基本型別時,傳的是值的拷貝,對拷貝變數的修改不影響原變數;當傳的是引用型別時,傳的是引用位址的拷貝,但是拷貝的位址和真實位址指向的都是同一個真實數據,因此可以修改原變數中的值;當傳的是String類型時,雖然拷貝的也是引用位址,指向的是同一個數據,但是String的值不能被修改,因此無法修改原變數中的值。

首先來解釋什麼是引用傳遞,什麼是值傳遞。

  • 引用傳遞(pass by reference)是指在呼叫方法時將實際參數的位址直接傳遞到方法中,那麼在方法中對參數所進行的修改,將會影響到實際參數。

  • 值傳遞(pass by value)是指在呼叫方法時將實際參數拷貝一份傳遞到方法中,這樣在方法中如果對參數進行修改,將不會影響到實際參數。

那在Java中到底是引用傳遞還是值傳遞呢?其實這個問題也一直是爭論不斷,而且官方也沒給個確切答案。但就我個人理解,Java是值轉遞。

我們先來看一個簡單的例子:

public void test() {
    int a = 1;
    change(a);
    System.out.println("a的值:" + a);
}
private void change(int a) {
    a = a + 1;
}
// 输出
a的值:1

在test()方法中定義了一個基本類型的變數a,然後呼叫change()方法試圖改變這個變量,最後輸出的還是原來的值。

首先我們要清楚,一個方法中的局部變數是存在堆疊中的,如果是基本型別的變數則直接存的是這個變數的值,如果是引用型別的變數則存的是值的位址,指向堆中具體的值。

上面的範例中,呼叫change()方法傳遞的a,其實是a變數的拷貝,不是真正的a,在change()方法中改變的是拷貝,對真正的a是沒有影響的。

這麼一看,Java確實是值傳遞,但我們再看下面這個例子,你就會糾結了

public void test() {
   User user = new User();
   user.setAge(18);
   change(user);
   System.out.println("年龄:" + user.getAge());
}
private void change(User user) {
   user.setAge(19);
}
// 输出
年龄:19

看,物件裡的屬性被改變了,不是值傳遞嗎,應該不會改變啊,這時候就有人總結了,當傳遞值是基本型別時是值傳遞、當傳的是引用型別時是引用傳遞。真的是這樣嗎?

分析這個問題,我們需要知道變數在jvm​​中是怎麼儲存的。

首先看基本類型,這個很簡單,變數在堆疊中直接存的是值,傳到change()方法的是這個變數的拷貝,因此對拷貝的變數修改不會影響原變數的值。

接著看引用類型,變數在堆疊中儲存的是引用位址,這個位址指向堆中具體的值,如下圖:

java是值傳遞還是引用傳遞

當調用change()方法傳入變數時,也是拷貝變量,但是這裡的拷貝只是堆疊中的引用位址,並不會拷貝堆中的數據,因此會變成下圖這樣:

java是值傳遞還是引用傳遞

雖然變數是拷貝,但是指向的位址是同一個,因此對變數中的資料修改時,還是會影響到原來真實的變量,但是,如果我們修改的是變數在堆疊中的位址,則不會影響原變量,例如下面這段程式碼:

public void test() {
   User user = new User();
   user.setAge(18);
   change(user);
   System.out.println("年龄:" + user.getAge());
}
private void change(User user) {
   user = new User();
   user.setAge(19);
}
// 输出
年龄:18

這種是修改變數在堆疊中的位址,則不會影響原變數。

說到這裡,大家差不多懂了,但是回頭看最開始的那個問題,傳入String類型的變量,String是引用類型,按道理,原變量是會被改變的呀,結果怎麼是不變呢?

String變數比較特殊,我們看String的源碼可以知道,String的值是透過內部的char[]陣列來維護的,但是這個資料定義的是final型別的,因此,String的值是不可變的。我們平常會修改String的值,其實是重新new了一個String對象,例如下面這段程式碼:

String a = "hello";
a = "world";

這段程式碼裡,其實a變數並沒有被修改成world,只是重新new了一個String對象,這個對象的值是world,並把這個對象的引用地址賦給了a,原來的hello還是在堆中,只是這個值沒有被引用,過段時間會被gc垃圾回收。

String變數傳值在記憶體中的變化如下圖:

java是值傳遞還是引用傳遞

String拷貝的是變數位址,但是它改變不了原String的值,因為String是不可變的,所以在change()方法中是重新new了一個String對象,改變的是新物件的值,原變數是沒有影響的。

更多相關知識,請造訪常見問題欄位!

以上是java是值傳遞還是引用傳遞的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn