1. 程式人生 > 其它 >轉:Java是值傳遞還是引用傳遞?

轉:Java是值傳遞還是引用傳遞?

技術標籤:Java# Java基本語法

Java是值傳遞還是引用傳遞?

參考:新增連結描述

值傳遞、引用傳遞以及JMM

值傳遞:當一個引數按照值的方式在兩個方法之間傳遞時,呼叫者和被呼叫者其實是用的兩個不同的變數——被呼叫者中的變數(原始值)是呼叫者中變數的一份拷貝,對它們當中的任何一個變數修改都不會影響到另外一個變數。
引用傳遞:當一個引數按照引用傳遞的方式在兩個方法之間傳遞時,呼叫者和被呼叫者其實用的是同一個變數,當該變數被修改時,雙方都是可見的。

JMM記憶體模型:

主記憶體:堆,存放共享資料,所有的物件和陣列都在堆上進行分配
工作記憶體:虛擬機器棧。存放執行緒私有基礎型別變數以及物件引用
方法區:儲存類的資訊、常量池、方法資料、方法程式碼等

Java 分為兩種資料型別,一種是基本型別,比如說 int;另外一種是引用型別,比如說 String。
基本型別的變數儲存的都是實際的值,而引用型別的變數儲存的是物件的引用——指向了物件在記憶體中的地址。值和引用儲存在 stack(棧)中,而物件儲存在 heap(堆)中。
在這裡插入圖片描述

之所以有這個區別,是因為:
• 棧的優勢是,存取速度比堆要快,僅次於直接位於 CPU 中的暫存器。但缺點是,棧中的資料大小與生存週期必須是確定的。
• 堆的優勢是可以動態地分配記憶體大小,生存週期也不必事先告訴編譯器,Java 的垃圾回收器會自動收走那些不再使用的資料。但由於要在執行時動態分配記憶體,存取速度較慢。

基本型別的引數傳遞

眾所周知,Java 有 8 種基本資料型別,分別是 int、long、byte、short、float、double 、char 和 boolean。它們的值直接儲存在棧中,每當作為引數傳遞時,都會將原始值(實參)複製一份新的出來,給形參用。形參將會在被呼叫方法結束時從棧中清除。
來看下面這段程式碼:

public class PrimitiveTypeDemo {
    public static void main(String[] args) {
        int age = 18;
        modify(age);
        System.out.println
(age); // 輸出18 } private static void modify(int age1) { age1 = 30; } }

呼叫 modify() 方法的時候,將為實參 age 建立一個副本(形參 age1),它的值也為 18,不過是在棧中的其他位置。對形參 age1 的任何修改都只會影響它自身而不會影響實參。

引用型別的引數傳遞

來看一段建立引用型別變數的程式碼:

Writer writer = new Writer(18, "a");

假如 writer 是物件的話,就不需要通過 new 關鍵字建立物件了。那也就是說,writer 並不是物件,在“=”操作符執行之前,它僅僅是一個變數。那誰是物件呢?new Writer(……),它是物件,儲存於堆中;然後,“=”操作符將物件的引用賦值給了 writer 變數,於是 writer 此時應該叫物件引用,它儲存在棧中,儲存了物件在堆中的地址。
每當引用型別作為引數傳遞時,都會建立一個物件引用(實參)的副本(形參),該形參儲存的地址和實參一樣。
來看下面這段程式碼:

public class ReferenceTypeDemo {
    public static void main(String[] args) {
        Writer a = new Writer(18);
        Writer b = new Writer(18);
        modify(a, b);
		System.out.println(a.getAge()); // 輸出30
        System.out.println(b.getAge());  // 輸出18
    }
	private static void modify(Writer a1, Writer b1) {
        a1.setAge(30);
		b1 = new Writer(18);
        b1.setAge(30);
    }
}

1)在呼叫 modify() 方法之前,實參 a 和 b 指向的物件是不一樣的,儘管 age 都為 18。

2)在呼叫 modify() 方法時,實參 a 和 b 都在棧中建立了一個新的副本,分別是 a1 和 b1,但指向的物件是一致的(a 和 a1 指向物件 a,b 和 b1 指向物件 b)。

3)在 modify() 方法中,修改了形參 a1 的 age 為 30,意味著物件 a 的 age 從 18 變成了 30,而實參 a 指向的也是物件 a,所以 a 的 age 也變成了 30;形參 b1 指向了一個新的物件,隨後 b1 的 age 被修改為 30。

修改 a1 的 age,意味著同時修改了 a 的 age,因為它們指向的物件是一個;修改 b1 的 age,對 b 卻沒有影響,因為它們指向的物件是兩個。