Java所有方法参数均为值传递,传递的是引用变量的副本而非对象本身或地址;String和Integer因不可变性,修改操作会新建对象,不影响原引用;而ArrayList等可变对象可通过副本引用修改堆中同一实例的内容。

Java 中所有方法参数都是值传递,没有例外。所谓“对象传引用”只是常见误解——实际上传递的是引用变量的副本,不是对象本身,更不是引用的地址。
为什么说 String 和 Integer 修改后原变量不变?
因为它们是不可变类(immutable),任何看似“修改”的操作(如 str.concat()、i++)都会新建对象,而形参只是指向新对象的副本,不影响实参变量所持有的旧引用。
-
String的concat()、substring()都返回新实例,原String对象未被改动 -
Integer是 final 类,i++实际等价于i = new Integer(i.intValue() + 1),赋值给的是形参变量,不改变调用方的栈上引用 - 即使传入
new Integer(42),方法内重新赋值i = 99,也不会影响外部变量
为什么 ArrayList 或自定义对象内部字段能被修改?
因为形参和实参**指向堆中同一个对象**,通过引用副本调用 add()、set() 或修改 obj.field = xxx,操作的是同一块堆内存。
- 传递的是引用值(即对象地址的拷贝),两个变量都持有该地址,因此可共同读写对象状态
- 但若在方法内执行
list = new ArrayList(),只是让形参指向新对象,实参仍指向原对象,不会影响外部 - 关键区分点:改“对象内容” ✅|改“引用指向” ❌(对实参无影响)
如何验证 Java 确实是纯值传递?
用一个可变对象配合地址打印(需借助 Unsafe 或 System.identityHashCode() 辅助观察),或直接看变量重赋值行为:
立即学习“Java免费学习笔记(深入)”;
public class PassByValueDemo {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("hello");
System.out.println("before: " + sb); // hello
modifyRef(sb);
System.out.println("after: " + sb); // hello world → 内容变了
}
static void modifyRef(StringBuilder s) {
s.append(" world"); // ✅ 修改对象内容,生效
s = new StringBuilder("oops"); // ❌ 只改形参指向,对外无效
}
}
如果 Java 是引用传递,最后一行赋值应让 sb 指向 "oops";但它没有——这正是值传递的铁证:你只能传值,哪怕这个值恰好是个引用。
真正容易混淆的点不在“传什么”,而在“能否通过它改东西”。重点盯住两件事:变量是否被重新赋值、操作是否落在对象实例上。其余说法,比如“基本类型传值、引用类型传地址”,都是不准确的简化,反而埋下理解隐患。









