在Java里值传递到底是什么意思_Java参数传递机制说明

Java只有值传递,即基本类型传数值、引用类型传地址副本;String修改不影响原变量因不可变性与地址重赋值,而Person字段修改影响原对象因操作同一堆内存。

Java 只有值传递,没有引用传递——这是铁律,不是“看起来像”或“某种程度上”。

为什么 String 修改后原变量不变?

因为 String 是不可变对象,且你传的是引用的副本。当你在方法里写 str = "new",只是让形参这个“地址副本”指向了新对象,原变量仍指着旧地址。

  • 实参 str1 存储的是堆中某个字符串对象的地址(比如 0x123)
  • 调用时,JVM 把 0x123 复制一份给形参 str1(现在有两个变量都存着 0x123)
  • 执行 str1 = "cba" → JVM 新建字符串对象,把新地址(比如 0x456)赋给形参 str1,但原变量 str1 还是 0x123

为什么 Person.age 改了,main 里也变了?

因为你没改引用本身,而是通过引用副本去修改了它指向的那个对象的内容——两个引用(实参和形参)仍指向同一块堆内存。

  • 实参 p1 和形参 p1 都存着同一个地址(比如 0x789)
  • p1.setAge(18) 是在堆地址 0x789 上改字段值,不是换地址
  • 所以 main 里的 p1 读到的还是同一块内存里的新值

怎么判断某次修改会不会影响原对象?

看你在方法里动的是「引用变量本身」,还是「引用所指对象的内部状态」。

  • ✅ 影响原对象:调用 list.add()sb.append()obj.setName() —— 操作堆中对象内容
  • ❌ 不影响原对象:写 list = new ArrayList()obj = new Person() —— 只重置了形参这个局部变量的地址值
  • ⚠️ 特别注意 String 和包装类(Integer 等):它们不可变,任何“修改”都会新建对象,本质都是重新赋值引用
public class PassByValueDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("hello")

; modifyContent(sb); // ✅ 改内容 → main 中 sb 变成 "hello world" System.out.println(sb); // 输出: hello world sb = new StringBuilder("hi"); // 重置引用 reassignRef(sb); // ❌ 重赋值 → main 中 sb 仍是 "hi" System.out.println(sb); // 输出: hi } static void modifyContent(StringBuilder sb) { sb.append(" world"); // 操作堆对象 } static void reassignRef(StringBuilder sb) { sb = new StringBuilder("bye"); // 只改形参的引用值 } }

最容易被绕晕的地方,是混淆「变量存的是什么」和「变量能干什么」:Java 里所有参数都是值传递,但这个“值”,对基本类型是数字本身,对引用类型是内存地址——地址也是值,只是它指向了别处。