java只有值传递,传递的是实参的值拷贝:基本类型拷贝数值,引用类型拷贝地址值;因此修改形参引用不影响实参,但通过引用修改对象状态会影响原对象。

Java中并不存在真正的“引用传递”,而是值传递,且传递的是对象引用的副本。这个基本事实决定了:对引用变量本身重新赋值(如 obj = new Object())不会影响调用方的原始引用;但通过该引用修改对象内部状态(如 list.add(x)、map.put(k, v)),会直接影响原对象——因为双方指向的是堆中同一个实例。
为什么说Java只有值传递
方法参数接收的永远是实参的值拷贝。对于基本类型,拷贝的是数值;对于引用类型,拷贝的是“指向对象的地址值”(即引用值),而非对象本身。因此:
- 修改形参引用指向新对象(
list = new ArrayList()),不影响实参引用 - 调用形参引用的方法改变其内部数据(
list.clear()、node.next = null),会影响实参所指对象的状态
常见数据结构中的典型表现
以下操作会跨方法边界生效,本质是共享同一堆内存:
-
ArrayList / LinkedList:调用
add()、remove()、set()、clear()后,原始列表内容立即变化 -
HashMap / TreeMap:执行
put()、remove()、computeIfAbsent()会更新原映射关系 -
自定义节点类(如链表Node、树TreeNode):修改
node.left、node.val等字段,直接反映在调用方持有的同一节点上
容易误判的边界情况
看似“修改了对象”,实则未影响原状态,关键看是否触发了对象内部字段变更:
-
String str = "a"; change(str);中若方法内写str = "b"—— 无影响(String不可变,只是改了形参指向) -
Integer i = 1; modify(i);中若写i++—— 无影响(自动装箱生成新Integer对象,原引用不变) -
int[] arr = {1}; arr = new int[]{2};—— 不影响原数组;但arr[0] = 99;会改变原数组首元素
如何安全控制状态可见性
若需避免意外修改,应主动隔离:
- 传入前做防御性拷贝:
new ArrayList(originalList)、new HashMap(originalMap) - 返回不可变视图:
Collections.unmodifiableList(list)、Map.copyOf(map)(Java 10+) - 对可变字段封装为private,仅提供受控的修改接口,或使用不可变数据结构(如Guava的ImmutableList)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南









