首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 值傳遞機制深度解析:為什麼說 Java 只有值傳遞

     編輯:Java 相關知識

前言:一道經典面試題的本質

「Java 是值傳遞還是引用傳遞?」 這個問題困擾了無數初學者。本文從 JVM 內存模型、棧幀結構、對象引用本質三個維度,徹底釐清 Java 參數傳遞機制。

一、核心結論

Java 只有值傳遞。傳遞基本類型時複製值本身;傳遞引用類型時複製引用的值(即對象地址),而非對象本身。

二、內存模型視角

1. 基本類型:棧上直接存值

void changeInt(int value) {
    value = 55; // 修改棧帧局部變量表槽位的值
}
int val = 11;
changeInt(val); // 實參 val 的值 (11) 複製給形參 value
// val 仍為 11
  • 基本類型變量直接存儲在棧幀局部變量表中。
  • 方法調用時,按值複製 到新棧幀的形參槽位,互不干擾。

2. 引用類型:棧存引用,堆存對象

void changeObj(PassTest ref) {
    ref.ptValue = 99f; // 通過引用修改堆上對象字段
}
PassTest pt = new PassTest();
pt.ptValue = 101f;
changeObj(pt); // 實參 pt 的引用值 (地址) 複製給形參 ref
// pt.ptValue 變為 99f
  • 引用變量 pt 在棧上,存儲對象在堆中的地址。
  • 調用時,地址值被複製 給形參 ref,兩個引用指向同一個堆對象。
  • 通過任一引用修改對象內部狀態,對方可見。

3. 關鍵區別:修改引用 vs 修改對象

void changeStr(String value) {
    value = new String("different"); // 形參 value 指向新對象
}
String str = "Hello";
changeStr(str);
// str 仍指向 "Hello",未變
  • value = new String(...) 只是修改局部引用變量 指向,不影響實參引用。
  • 這正是「引用傳遞」支持者誤以為的「引用被修改」——實際上是引用的值(地址)被複製,修改副本不影響原引用。

三、對比 C/C++ 指針傳遞

語言機制能否修改實參引用指向
C值傳遞 (可傳指針地址)✅ void f(int **p)
C++引用傳遞 / 指針傳遞✅ void f(int*& p)
Java值傳遞 (引用值不可變)❌ 無語法機制修改實參引用

四、工程實踐啟示

  1. 不可變對象:String、Integer、LocalDate 等不可變類,傳遞安全,無副作用。
  2. 可變對象傳遞:集合、實體類、StringBuilder 等,明確文檔所有權:是調用方負責不可變性,還是被調用方可修改?
  3. 防禦性拷貝:構造器/Setter/Getters 對可變參數/返回值進行拷貝,避免內部狀態洩露。
    public void setList(List list) {
        this.list = new ArrayList<>(list); // 防禦性拷貝
    }
  4. 不要試圖在方法中「替換」實參對象:obj = new Obj() 無效,應返回新對象或使用包裝類/數組/AtomicReference。

五、總結

Java 參數傳遞 = 值傳遞。理解「引用值複製」與「對象共享」的邊界,是寫出無副作用、線程安全代碼的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved