Java中方法参数传递均为值传递,即基本类型传数值副本、引用类型传地址副本;修改对象属性会影响实参,但重新赋值形参(如new对象)则不影响实参。

Java 中方法间传递复杂对象,用的不是引用传递,而是值传递——只不过传的是“对象地址的副本”。理解这点,就能避开绝大多数参数修改失效的问题。
传递的是地址副本,不是对象本身
当你把一个 Person、ArrayList 或自定义类实例传进方法时,JVM 并没有把整个对象拷贝过去,也没有把变量本身的“引用”直接交给方法。它做的是:把该对象在堆内存中的地址(比如 0x7a8b9c)复制一份,存到方法的栈帧里作为形参变量的值。
- 实参变量和形参变量是两个独立的栈变量,各自有各自的内存地址
- 但它们存储的值相同——都是指向堆中同一个对象的地址
- 就像你和同事各拿一张同一间办公室的门卡,卡不一样,但开的是同一扇门
改对象内容,外部可见;改引用本身,外部无感
正因为形参和实参指向同一块堆内存,所以操作对象内部状态会同步体现:
-
p.name = "李四"→ 修改的是堆中那个 Person 实例的字段,main 里的 p.name 也会变成 "李四" -
list.add("item")→ 调用的是堆中同一个 ArrayList 对象的方法,元素确实加进去了 -
arr[0] = 100→ 数组是对象,改的是堆中数组元素,原数组跟着变
但一旦你让形参“换把钥匙”:
立即学习“Java免费学习笔记(深入)”;
-
p = new Person("王五")→ 形参 p 现在指向新对象,实参仍锁着旧对象 -
list = new ArrayList()→ 方法内 list 指向新集合,原 list 不受影响 -
str = "hello"→ String 不可变,赋值实际是新建字符串对象并重定向形参,原 str 不变
数组和包装类也遵循同一规则
别被类型迷惑,关键看底层机制:
- 数组是引用类型:
arr[2] = 5生效(改堆中内容),arr = new int[3]失效(只改形参地址) - Integer、Boolean 等包装类也是引用类型,但不可变:
i = i + 1本质是拆箱→计算→装箱→新建对象→形参指向新地址,原变量不变 - String 同理,所有“赋值”操作都产生新对象,原引用不受影响
为什么说 Java 没有引用传递?
真正的引用传递,是指方法拿到的是变量本身的内存地址,能直接修改变量指向。而 Java 中:
- 形参永远无法改变实参变量的栈中存储值(即那个地址)
- 哪怕你在方法里写
p = null,main 里的 p 还是原来那个对象的地址 - 这是 JVM 栈帧隔离机制决定的,也是 Java 语言规范明确规定的:所有参数都是值传递


















