原文来自于:zha-ge.cn/java/26
Java 方法传参,到底是值还是引用?
面试中的困惑
那天在面试中,技术官问了一个看似简单的问题:"Java 方法传参是值传递还是引用传递?"
我自信满满地回答:"基本类型是值传递,对象是引用传递!"
面试官微笑着在白板上写下了这段代码:
java
public void swap(Integer a, Integer b) {
Integer temp = a;
a = b;
b = temp;
}
// 调用
Integer x = 10, y = 20;
swap(x, y);
System.out.println("x=" + x + ", y=" + y); // 结果是什么?
"你觉得 x 和 y 会交换吗?" 面试官问道。
我愣住了。按照我的理解,Integer 是对象,应该是引用传递,x 和 y 应该会交换才对!
真相:被"引用传递"误导
结果当然没变,输出是 x=10, y=20
,根本没有交换!
这时我意识到,我对 Java 传参机制的理解有误。面试官接着展示了另一个例子:
java
public void modifyList(List<String> list) {
list.add("新元素");
list = new ArrayList<>(); // 重新赋值
list.add("这个不会影响原list");
}
List<String> myList = new ArrayList<>();
myList.add("原始元素");
modifyList(myList);
// myList 里有什么?
答案是 ["原始元素", "新元素"]
。第二个赋值操作并没有影响到原来的 list!
Java 只有值传递
面试官解释说:Java 中永远只有值传递,没有引用传递!
理解"值"的关键在于:
- 基本类型:传递的是数据本身的副本
- 对象类型:传递的是引用地址的副本
用快递来比喻:
传参类型 | 比喻 | 实际情况 |
---|---|---|
基本类型 | 给你一份文件的复印件 | 修改副本不影响原件 |
对象类型 | 给你一张地址纸条的复印件 | 通过地址能找到同一个房子,但换掉纸条不影响原地址 |
核心理解:引用的副本 ≠ 引用传递
看这段代码:
java
public void testReference(StringBuilder sb) {
sb.append("_modified"); // 能修改对象内容
sb = new StringBuilder("new"); // 重新赋值不影响外部
}
StringBuilder original = new StringBuilder("hello");
testReference(original);
System.out.println(original); // 输出: hello_modified
为什么 append
有效而重新赋值无效?
因为方法接收的是引用地址的副本:
- 可以通过这个副本地址修改同一个对象
- 但改变副本本身(重新赋值),不会影响原来的引用
经验总结
这次面试让我明白:
- 概念要精准:Java 没有 C++ 的引用传递,统一都是值传递
- 区分对象和引用:修改对象内容与改变引用指向效果不同
- 包装类的注意事项:Integer、String 等不可变对象,重新赋值不会影响原值
现在每当有人问起 Java 传参机制,我都会先讲这个 swap 的故事,然后强调:
Java 只有值传递,对象传递的是引用地址的值!
理解这一点后,很多困惑就迎刃而解了。你是否也曾被这个概念困扰过呢?