深克隆和浅克隆有什么区别?
- 浅克隆
- 把原型对象中成员变量为值的属性复制给克隆对象
- 把原型对象中成员变量为引用的引用地址复制给克隆对象
- 深克隆
- 把原型对象中的所有类型(无论是值还是引用类型)都复制一份给克隆对象
- 把原型对象中的所有类型(无论是值还是引用类型)都复制一份给克隆对象
java.lang.Object 中对 clone() 方法的约定有哪些?
对于所有对象来说
x.clone()!=x
,因为克隆对象与源对象不是同一个对象x.clone.getClass() == x.getClass()
,因为克隆对象与原对象类型一致x.clone().equals(x)
,因为equals比较的时他们的值,都是相同的
Arrays.copyOf()是实现深克隆还是浅克隆
- Arrays.copyOf()是浅克隆,只是将数组的引用地址复制给了克隆对象,如果克隆对象发生修改,原对象也会发生改变
深克隆实现方式有哪些?
-
所有的对象和对象内的引用对象都实现了克隆方法
- 复制的对象必须实现了Cloneable接口,并重写了clone方法
- 复制的对象的属性中为引用的对象也必须重写了clone方法
代码演示
复制了一个people类,并修改了其属性对象的属性,但是原对象并没有发生修改
public class Solution {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("中国", "成都");
People people = new People(address, "张三");
People people2 = people.clone();
people2.getAddress().setCity("德阳");
System.out.println("people:"+people.getAddress().getCity());
System.out.println("people2:"+people2.getAddress().getCity());
}
}
class People implements Cloneable {
private Address address;
private String username;
@Override
protected People clone() throws CloneNotSupportedException {
People people = (People) super.clone();
people.setAddress((Address) this.address.clone());
return people;
}
//忽略构造、set、get
}
class Address implements Cloneable {
private String country;
private String city;
@Override
protected Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
//忽略构造、set、get
}
运行结果
people:成都
people2:德阳
- 通过构造方法实现深克隆
不调用方法复制对象,而是采用构造方法,将原对象的属性一个一个设置进去
代码演示:
public class Solution {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("中国", "成都");
People people = new People(address, "张三");
People people2 = new People(
new Address(address.getCountry(), address.getCity()),
people.getUsername());
people2.getAddress().setCity("德阳");
System.out.println("people:"+people.getAddress().getCity());
System.out.println("people2:"+people2.getAddress().getCity());
}
}
class People {
private Address address;
private String username;
//忽略构造、set、get
}
class Address {
private String country;
private String city;
//忽略构造、set、get
}
运行结果
people:成都
people2:德阳
- 通过JDK自带的字节流实现深克隆
通过输入输出流自己实现一个工具类,较为繁琐,可以使用第三方写好的工具类实现
- 使用第三方工具,以 Apache Commons Lang为例
- 添加相关依赖
- 克隆对象都必须序列化,包括对象的属性引用的对象
public class Solution {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("中国", "成都");
People people = new People(address, "张三");
People people2 = (People)SerializationUtils.clone(people);
people2.getAddress().setCity("德阳");
System.out.println("people:"+people.getAddress().getCity());
System.out.println("people2:"+people2.getAddress().getCity());
}
}
class People implements Serializable {
private Address address;
private String username;
//忽略构造、set、get
}
class Address implements Serializable{
private String country;
private String city;
//忽略构造、set、get
}
- 使用JSON工具类实现深克隆,如Gson,FastJSON等
public class Solution {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("中国", "成都");
People people = new People(address, "张三");
Gson gson = new Gson();
People people2 = gson.fromJson(gson.toJson(people),People.class);
people2.getAddress().setCity("德阳");
System.out.println("people:"+people.getAddress().getCity());
System.out.println("people2:"+people2.getAddress().getCity());
}
}