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读到的还是同一块内存里的新值
怎么判断某次修改会不会影响原对象?
看你在方法里动的是「引用变量本身」,还是「引用所指对象的内部状态」。
立即学习“Java免费学习笔记(深入)”;
- ✅ 影响原对象:调用
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 里所有参数都是值传递,但这个“值”,对基本类型是数字本身,对引用类型是内存地址——地址也是值,只是它指向了别处。










