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

Java 變數值交換原理與實作:值傳遞機制深度解析與三種交換方案

     編輯:Java 相關知識

Java 參數傳遞機制鐵律

Java 唯一支援「值傳遞」:方法接收的是所有參數值的副本,無法修改呼叫端變數本身的引用/值。

兩類參數傳遞行為對比

參數類型傳遞內容方法內可否修改呼叫端變數方法內可否修改物件狀態
基本型別值的副本不可不適用
物件引用引用的副本(指向同一物件)不可(無法讓引用指向新物件)可(透過引用修改物件內部狀態)

驗證程式碼:物件引用值傳遞

class MyClass {
    private Object value;
    public MyClass(Object v) { this.value = v; }
    public Object getValue() { return value; }
    public void setValue(Object v) { this.value = v; }
}

public class ParamPassingDemo {
    // 修改物件狀態:成功
    static void changeState(MyClass obj) {
        obj.setValue(100); // 修改同一物件的內部欄位
    }
    
    // 嘗試交換引用:失敗
    static void swapRef(MyClass a, MyClass b) {
        MyClass temp = a;
        a = b;      // 僅修改區域變數 a 的引用
        b = temp;   // 呼叫端原始變數完全不受影響
    }
    
    public static void main(String[] args) {
        MyClass x = new MyClass(10);
        MyClass y = new MyClass(100);
        
        System.out.println("呼叫 changeState 前: x=" + x.getValue() + ", y=" + y.getValue());
        changeState(x);
        System.out.println("呼叫 changeState 後: x=" + x.getValue() + ", y=" + y.getValue()); // x 變 100
        
        System.out.println("呼叫 swapRef 前: x=" + x.getValue() + ", y=" + y.getValue());
        swapRef(x, y);
        System.out.println("呼叫 swapRef 後: x=" + x.getValue() + ", y=" + y.getValue()); // 無變化
    }
}

三種正確交換變數值的方案

方案一:修改物件內部狀態(適用可變物件)

static void swapState(MyClass a, MyClass b) {
    Object temp = a.getValue();
    a.setValue(b.getValue());
    b.setValue(temp);
}
// 呼叫端:x、y 引用不變,但內部 value 已交換

方案二:使用陣列/容器包裝(模擬引用傳遞)

static void swapWrapper(MyClass[] arr) {
    MyClass temp = arr[0];
    arr[0] = arr[1];
    arr[1] = temp;
}

// 呼叫端:
MyClass[] wrapper = {x, y};
swapWrapper(wrapper);
x = wrapper[0];
y = wrapper[1];

方案三:返回新物件/結果物件(函數式風格)

// 返回交換後的陣列
static MyClass[] swapReturn(MyClass a, MyClass b) {
    return new MyClass[]{b, a};
}

// 呼叫端:
MyClass[] swapped = swapReturn(x, y);
x = swapped[0];
y = swapped[1];

方案四:基本型別交換(需返回結果)

// 錯誤:無法交換基本型別
static void swapPrimitive(int a, int b) { int t=a; a=b; b=t; }

// 正確:返回交換結果
static int[] swapPrimitiveReturn(int a, int b) {
    return new int[]{b, a};
}

// 或使用 AtomicInteger 等包裝類
static void swapAtomic(AtomicInteger a, AtomicInteger b) {
    int temp = a.get();
    a.set(b.get());
    b.set(temp);
}

記憶體模型圖解

// 呼叫端棧幀                    方法棧幀                    堆疊
// ┌─────────────┐              ┌─────────────┐              ┌─────────────┐
// │ x ──────────┼─────────────►│ objRef ─────┼─────────────►│ MyClass@100 │
// │             │   值傳遞副本  │             │   同一引用    │ value: 10   │
// │ y ──────────┼─────────────►│ objRef2 ────┼─────────────►│ MyClass@200 │
// └─────────────┘              └─────────────┘              │ value: 100  │
//                                                          └─────────────┘

// swapRef 內部:
// objRef ← objRef2  (僅區域變數指向改變,呼叫端 x、y 完全不受影響)

最佳實踐建議

  1. 理解值傳遞本質:不嘗試在方法中修改呼叫端變數引用
  2. 優先用不可變物件:避免狀態修改帶來的副作用
  3. 需交換時返回結果:函數式風格 return new Pair(b, a) 最清晰
  4. 可變物件謹慎共享:明確文檔標註方法是否修改參數物件狀態
  5. 基本型別交換:直接返回陣列/容器,或使用 AtomicInteger 等包裝類

常見面試陷阱題

程式碼片段輸出結果解析
swap(int a, int b) { int t=a; a=b; b=t; }無效果基本型別值傳遞
swap(Integer a, Integer b) { ... }無效果Integer 不可變,引用值傳遞
swap(StringBuilder a, StringBuilder b) { a.append(b); b.append(a); }修改內容可變物件,修改內部狀態
swapObj(MyObj a, MyObj b) { a=b; }無效果引用副本重新指向
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved