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

Java 參數傳遞本質:值傳遞鐵律與對象引用的「偽」引用傳遞

     編輯:Java 相關知識

面試經典題

public class PassByValueDemo {
    public static void stringUpd(String str) {
        str = str.replace("j", "l"); // 生成新字符串
        System.out.println("方法內: " + str); // lava
    }

    public static void sbUpd(StringBuffer sb) {
        sb.append("c"); // 修改對象內部狀態
        System.out.println("方法內: " + sb); // javac
    }

    public static void main(String[] args) {
        String s = "java";
        stringUpd(s);
        System.out.println("方法外: " + s); // java ← 未變

        StringBuffer sb = new StringBuffer("java");
        sbUpd(sb);
        System.out.println("方法外: " + sb); // javac ← 已變
    }
}

核心結論

Java 唯一支援「值傳遞」。基本類型傳值的副本,引用類型傳引用的副本(即地址值副本)。

圖解內存模型

String s = "java"          StringBuffer sb = new StringBuffer("java")
┌─────────┐                ┌─────────┐     ┌──────────────────┐
│  s  ───┼──► "java" (常量池/堆)   │  sb  ───┼──► [java] (堆對象) │
└─────────┘                └─────────┘     └──────────────────┘

調用 stringUpd(s)        調用 sbUpd(sb)
┌─────────┐                ┌─────────┐
│ str ────┼──► "java"      │ sbParam ┼──► [java] (同一對象)
└─────────┘                └─────────┘
str = "lava" (新對象)      sb.append("c") → [javac]
外部 s 仍指向 "java"       外部 sb 見到變更

關鍵區別

操作基本類型 / String可變對象
參數賦新值 改變局部引用指向,不影響外部 改變局部引用指向,不影響外部
調用方法修改內部狀態 不可變類無此操作 影響外部原對象(共享堆內存)
典型類 int, double, String, Integer, Long... StringBuffer, ArrayList, HashMap, 自定義 Bean

實戰避坑指南

  1. 別嘗試在方法內「替換」外部引用:
    // 錯誤示範
    public void swap(User a, User b) {
        User tmp = a; a = b; b = tmp; // 僅交換局部引用,外部無感
    }
    // 正確:修改對象內部字段,或返回新對象
  2. 集合傳遞陷阱:
    public void addItem(List<String> list) {
        list = new ArrayList<>(); // 切斷與外部關聯
        list.add("new"); // 外部列表無變化
    }
    public void addItemCorrect(List<String> list) {
        list.add("new"); // 修改共享對象,外部可見
    }
  3. 不可變對象安全性:String、包裝類、LocalDate 等不可變,天然線程安全,傳遞無副作用風險

JVM 視角補充

  • 棧幀:每次方法調用分配新棧幀,局部變量表存放參數副本
  • 堆內存:對象實體存儲地,引用變量存的是堆地址(oop)
  • 逃逸分析:JIT 可能將未逃逸對象標量替換、棧上分配,但語義不變

總結

Java 只有值傳遞。理解「引用值副本」與「對象實體」的區別,是寫出無 Bug 代碼的基石。面試時若能畫出棧/堆示意圖並說清 String vs StringBuffer 差異,即可拿下此考點。

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