备忘录五
前言 简单记录一下Android给第三方应用白名单授权的代码...
简单记录一下Java面试中的克隆,已经对象的深拷贝和浅拷贝相关的知识。
记录于此,方便自己查阅和学习。
下面分别介绍一下克隆,深拷贝和浅拷贝相关知识。
定义:克隆就是创建一个对象的副本
Java 提供了Object.clone()方法
要使用克隆,类必须实现 Cloneable接口
Cloneable是一个 标记接口(Marker Interface)
未实现Cloneable调用clone()会抛CloneNotSupportedException
定义:只复制对象本身和基本类型字段,引用类型字段仍然指向原对象
示例
class Address { String city; } class Person implements Cloneable { int age; Address address; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 默认浅拷贝 } } Person p1 = new Person(); p1.address = new Address(); p1.address.city = "Beijing"; Person p2 = (Person) p1.clone(); p2.address.city = "Shanghai"; System.out.println(p1.address.city); //输出:Shanghai
原因:address是引用类型,拷贝的是引用地址
p2指向了pi的地址
定义:不仅复制对象本身,还递归复制引用类型字段,新对象与原对象完全独立
重写 clone()
class Address implements Cloneable { String city; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { int age; Address address; @Override protected Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.address = (Address) this.address.clone(); // 关键 return person; } }
修改p2.address不会影响p1。
序列化
// 所有对象实现 Serializable ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(person); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); Person deepCopy = (Person) ois.readObject();
自动深拷贝
缺点:性能差、代码重、不适合复杂对象
手动new
Person copy = new Person(); copy.age = this.age; copy.address = new Address(); copy.address.city = this.address.city;
优点:可读性好、可控、无反射/序列化风险
| 对比点 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 对象本身 | 新对象 | 新对象 |
| 基本类型 | 复制值 | 复制值 |
| 引用类型 | 共享引用 | 新建对象 |
| 修改引用对象 | 互相影响 | 互不影响 |
| 实现难度 | 简单 | 较复杂 |
| 性能 | 快 | 慢 |
浅拷贝复制引用,深拷贝复制对象;Java 默认是浅拷贝,深拷贝需要自己实现。
克隆是通过Object.clone()创建对象副本的一种方式
Java中默认的clone()是浅拷贝,只会复制对象本身和基本类型字段,引用类型字段仍然指向原对象
深拷贝会在拷贝对象的同时,递归复制引用对象,使新对象与原对象完全独立
实现深拷贝可以通过重写 clone()、手动 new 对象,或者通过序列化完成。
Cloneable是标记接口
JVM用它判断是否允许克隆
否则抛 CloneNotSupportedException
默认是浅拷贝
易破坏封装
构造器更安全
推荐使用构造函数 / Builder / 拷贝工具
不一定
性能开销大
循环引用问题
实际业务大多只需要“部分拷贝”