前言
Java面试中常见的问题就是关于「值拷贝」和「地址拷贝」,简单记录于此,方便自己查阅和学习。
正文
先说结论:
Java 只有「值拷贝」,没有「地址拷贝」
Java 永远是 pass-by-value(值传递)
基本类型
基本类型拷贝的就是「值本身」
int a = 10; int b = a; b = 20; System.out.println(a); // 10
- a的值是 10
- b得到的是 10的副本
- 互不影响
完完全全的值拷贝
引用类型
引用类型拷贝的「引用的值」
Person p1 = new Person("Tom"); Person p2 = p1; p2.setName("Jerry"); System.out.println(p1.getName()); // Jerry
发生了什么:
栈: p1 ──┐ ├──► 堆中的 Person 对象 p2 ──┘
- p1存的是 对象在堆中的地址值
- p2 = p1拷贝的是 这个地址值
- 两个引用指向 同一个对象
仍然是值拷贝,只是值是“地址”
方法传参
Java 是值传递
基本类型
void change(int x) { x = 100; } int a = 10; change(a); System.out.println(a); // 10
方法里改的是 形参的副本
引用类型
void change(Person p) { p.setName("Changed"); } Person person = new Person("Tom"); change(person); System.out.println(person.getName()); // Changed
关键点:
- p是 person的 引用值拷贝
- 指向的是 同一个对象
- 所以对象内容会变
传对象
void change(Person p) { p = new Person("New"); } Person person = new Person("Tom"); change(person); System.out.println(person.getName()); // Tom
原因:
- p只是引用的副本
- 改 p指向新对象,不影响原引用
再次证明:Java 是值传递
匿名类中的拷贝
当你在匿名类中访问局部变量:
int x = 10; Runnable r = () -> System.out.println(x);
本质是:
class Inner { private int val$x; Inner(int x) { this.val$x = x; } }
- 拷贝的是值,不是变量本身
- 所以变量不能再改(final / effectively final)
小结
| 场景 | 拷贝的是什么 |
|---|---|
| 基本类型 | 数值本身 |
| 引用类型 | 引用的值(地址值) |
| 方法参数 | 永远都是值拷贝 |
| Java 整体 | 只有值传递 |
Java 没有地址拷贝,只有“值拷贝 + 引用的值”
参考文章
暂无评论...
