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

Java 參數傳遞機制深度解析:到底是值傳遞還是引用傳遞?

     編輯:Java 綜合教學

Java 參數傳遞機制深度解析

「Java 是值傳遞還是引用傳遞?」這是面試必考、開發易踩的經典話題。結論先行:Java 只有值傳遞。本文通過內存模型圖解與代碼實證,徹底釐清基本類型、對象引用、不可變對象三類場景的傳遞本質。

一、核心結論:只傳值,不傳引用

  • 基本類型:直接複製數值(bit-by-bit);
  • 引用類型:複製引用地址值(即指針),而非對象本身;
  • 方法內對參數的重新賦值(指向新對象)不影響實參;
  • 方法內通過引用修改對象內部狀態(調用 setter、集合 add 等)會影響實參指向的同一對象。

二、經典案例逐幀分析

public class Person {
    private String name;
    public Person(String name) { this.name = name; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

public class ParamTest {
    public static void changeName1(Person p) {      // 修改對象內部狀態
        p.setName("Bob");
    }

    public static void changeName2(Person p) {      // 重新賦值參數
        Person another = new Person("Tom");
        p = another;                                // 僅改變局部引用指向
    }

    public static void main(String[] args) {
        Person person = new Person("Lily");         // 地址 0x60
        changeName1(person);                        // 0x60 內 name → "Bob"
        System.out.println(person.getName());       // Bob ✅

        changeName2(person);                        // 參數 p 複製 0x60,內部 p 指向 0x65
        System.out.println(person.getName());       // Bob ✅ 未變
    }
}

內存圖解

main 棧幀                    changeName2 棧幀
┌──────────────────┐         ┌──────────────────┐
│ person ──┐       │         │ p (參數) ──┐     │
└──────────│───────┘         └────────────│─────┘
           │                              │
           ▼                              ▼ (賦值後)
      ┌─────────┐                    ┌─────────┐
 0x60 │ name="Bob"│               0x65 │ name="Tom"│
      └─────────┘                    └─────────┘

關鍵:p = another 只是將棧幀局部變量 p 指向新地址 0x65,主方法的 person 仍指向 0x60,互不干擾。

三、不可變對象(String、Integer 等)的特殊性

public static void testString(String s) {
    s = "changed";           // 重新賦值,創建新字符串對象
}
public static void testInteger(Integer i) {
    i = 200;                 // 自動拆箱/裝箱生成新 Integer 對象
}

因為不可變類無任何修改內部狀態的方法,所以外部感知上「像值傳遞」,本質仍是引用地址值傳遞。

四、面試必答話術模板

「Java 嚴格採用按值調用。方法接收的是實參值的副本:基本類型複製數值,引用類型複製對象地址。因此:
  1. 方法內重新賦值參數(指向新對象)不影響外部;
  2. 方法內通過引用修改對象可變狀態(如 setter、集合操作)會影響外部共享對象;
  3. 對於不可變對象,無修改狀態手段,行為等同於值傳遞。
這設計在保證簡單性的同時,避免了 C++ 指針/引用的複雜性與風險。」

五、實戰最佳實踐

  1. 方法參數盡量不可變(final 修飾),避免誤重新賦值;
  2. 需修改調用者變量時,返回新對象或使用包裝類(如 AtomicReference、單元素數組 T[]);
  3. 集合/Map 做參數時,明確文檔說明「是否允許修改內部元素」,必要時傳入 Collections.unmodifiableList();
  4. 大對象傳遞無性能顧慮(僅複製 8 字節引用),但注意逃逸分析可能導致標量替換優化。
「參數傳遞看似微觀,實則關繫系統邊界的契約設計。守住『不隨意修改入參狀態』原則,微服務介面也會更乾淨。」
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved