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

Java 核心面試題:值傳遞 vs 引用傳遞 徹底講透

     編輯:Java 程式設計入門

一句话結論

Java 只有值傳遞。對於基本類型傳遞值的副本;對於引用類型傳遞引用的副本(即對象地址的副本)。

基本類型:值的副本,互不影響

public class PrimitiveDemo {
    public static void main(String[] args) {
        int a = 3;
        modify(a);
        System.out.println("main 中 a = " + a); // 輸出 3
    }

    static void modify(int x) {
        x = 5;
        System.out.println("modify 中 x = " + x); // 輸出 5
    }
}

內存圖解:main 棧幀中 a=3;調用 modify 時在新棧幀創建 x 並複製值 3。修改 x 不影響 a。

引用類型:引用副本,指向同一對象

class Person {
    String name;
    Person(String name) { this.name = name; }
}

public class ReferenceDemo {
    public static void main(String[] args) {
        Person p = new Person("Alice");
        changeName(p);
        System.out.println("main 中 p.name = " + p.name); // 輸出 Bob
    }

    static void changeName(Person person) {
        person.name = "Bob"; // 修改對象內部狀態
    }
}

關鍵點:person 是 p 的副本,但兩個引用指向堆上同一個 Person 對象。通過副本修改對象字段,主方法可見。

引用類型陷阱:重新賦值引用不影響原變量

public class ReferenceTrap {
    public static void main(String[] args) {
        Person p = new Person("Alice");
        replace(p);
        System.out.println("main 中 p.name = " + p.name); // 仍輸出 Alice
    }

    static void replace(Person person) {
        person = new Person("Bob"); // person 變量指向新對象
        person.name = "Charlie";
    }
}

內存圖解:

  1. main 棧幀 p → 堆地址 0x100 (Alice)
  2. 調用 replace,棧幀創建 person,複製地址 0x100
  3. person = new Person("Bob") → person 指向新地址 0x200
  4. 後續操作針對 0x200,main 的 p 仍指向 0x100,完全不受影響

String 特殊性:不可變 + 常量池

public class StringDemo {
    public static void main(String[] args) {
        String s = "Hello";
        modifyString(s);
        System.out.println(s); // 輸出 Hello
    }

    static void modifyString(String str) {
        str = str + " World"; // 產生新字符串對象
        // str += " World"; 同理
    }
}

String 為 final 類,任何「修改」操作實際創建新對象,原引用不變,故表現同基本類型——傳值(引用值)不可變。

面試高頻追問與回答模板

問題標準回答要點
Java 是值傳遞還是引用傳遞?只有值傳遞。基本類型傳值副本;引用類型傳引用副本(地址副本)。
為什麼方法內修改對象屬性外部可見?引用副本指向同一堆對象,通過副本訪問對象內部字段/方法修改狀態。
為什麼方法內 new 新對象賦值給參數,外部引用不變?參數變量持有引用副本,重新賦值只改變副本指向,不影響原引用指向。
如何在方法內修改外部引用指向?Java 不支持。替代方案:返回新對象、使用包裝類(AtomicReference)、集合/數組容器、或重新設計 API。

實戰最佳實踐

  1. 不可變對象優先:如 String、包裝類、自定義不可變類,天然線程安全,無副作用。
  2. 防御性複製:方法接收可變對象參數時,內部拷貝一份再操作,避免外部竄改內部狀態。
  3. 避免「輸出參數」模式:Java 無 out/ref 關鍵字,需修改對象狀態請直接修改傳入對象,或返回新對象。
  4. 集合/數組傳遞:傳遞的是引用副本,方法內 list.add() 影響外部;list = new ArrayList() 不影響外部。

總結

Java 僅支持值傳遞。理解「引用副本指向同一對象」與「重新賦值引用副本不影響原引用」的區別,是寫出正確、無副作用代碼的核心。面試時畫棧/堆內存圖,條理清晰講清三種情況(基本類型、引用修改狀態、引用重新賦值),即可拿下此題。

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