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

Java 形參與實參傳遞機制深度解析:基本類型與引用類型的差異

     編輯:程式設計綜合問答

核心結論:Java 只有「值傳遞」

Java 中方法參數傳遞永遠是「值傳遞」。但「值」的含義因類型不同而異:

  • 基本類型:傳遞的是**數值本身的副本**。方法內修改形參,**不影響**實參。
  • 引用類型:傳遞的是**對象引用 (地址) 的副本**。方法內:
    • 修改形參指向 (如 `param = new Object()`):**不影響**實參指向。
    • 通過形參調用方法修改對象內部狀態 (如 `param.setName("new")`):**影響**實參指向的同一對象。

三個問題逐一解答

1. 實參會隨著形參改變而改變嗎?

  • 基本類型:**不會**。形參是副本,修改獨立。
  • 引用類型:
    • 若方法內**重新賦值形參** (`param = new Obj()`):**不會**,實參仍指向原對象。
    • 若方法內**調用形參方法修改對象內容** (`param.setX(1)`):**會**,實參指向的對象被修改。

2. 多線程中實參改變,線程內形參變嗎?

**同理**。關鍵在於「改變」的含義:

  • 主線程將實參引用指向**新對象** (`ref = new Obj()`):子線程形參仍指向**舊對象** (引用副本未變)。
  • 主線程調用實參方法**修改對象內容** (`ref.modify()`):子線程形參指向**同一對象**,可見修改 (需考慮線程安全:`volatile`、`synchronized`、不可變對象)。

3. 基本類型 vs 非基本類型 (引用類型) 一樣嗎?

**不一樣**,核心差異如上。補充說明:

  • String 是特殊的引用類型:不可變。任何「修改」操作 (`str = str + "a"`, `str.replace()`) 實際都是創建**新 String 對象**,原對象不變。因此傳遞 String 給方法,方法內無法修改原字符串對象,也無法讓實參指向新字符串 (除非返回新值並重新賦值)。
  • 包裝類 同 String,不可變。
  • 數組、集合、自定義類** 可變,方法內可修改內容影響實參。

代碼驗證

public class ParamTest {
    // 基本類型
    static void primitive(int x) { x = 20; }
    // 引用類型 - 重新賦值
    static void refReassign(StringBuilder sb) { sb = new StringBuilder("new"); }
    // 引用類型 - 修改內容
    static void refModify(StringBuilder sb) { sb.append(" modified"); }
    // String (不可變引用)
    static void stringTest(String s) { s = "changed"; }

    public static void main(String[] args) {
        int a = 10; primitive(a); System.out.println(a); // 10 不變

        StringBuilder b = new StringBuilder("old");
        refReassign(b); System.out.println(b); // "old" 不變

        StringBuilder c = new StringBuilder("old");
        refModify(c); System.out.println(c); // "old modified" 變了!

        String d = "hello"; stringTest(d); System.out.println(d); // "hello" 不變
    }
}

多線程場景最佳實踐

  • **不可變對象**:傳遞 `final` 引用指向不可變對象 (String、包裝類、Guava ImmutableList、自定義不可變類),天然線程安全。
  • **可變對象 + 線程封閉**:對象僅由單線程訪問,或使用 `ThreadLocal` 隔離副本。
  • **可變對象 + 同步**:加鎖 (`synchronized`、`ReentrantLock`)、使用並發容器 (`ConcurrentHashMap`)、原子類 (`AtomicInteger`)。
  • **防御性拷貝**:方法邊界進出時拷貝可變對象 (`new ArrayList<>(list)`、`obj.clone()`),切斷共享引用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved