浅拷贝
浅拷贝会在堆上创建一个新的对象(区别于深拷贝的一点),如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是拷贝对象和原对象共用同一个内部对象。
public class Address implements Cloneable{
private String name;
// 省略构造函数、Getter&Setter方法
@Override
public Address clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
public class Person implements Cloneable {
private Address address;
// 省略构造函数、Getter&Setter方法
@Override
public Person clone() {
try {
Person person = (Person) super.clone();
return person;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
测试
Person person1 = new Person(new Address("武汉"));
Person person1Copy = person1.clone();
// true
System.out.println(person1.getAddress() == person1Copy.getAddress());
从输出结构来看person1的克隆对象和person1使用的仍然是同一个Address对象。
深拷贝
深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
@Override
public Person clone() {
try {
Person person = (Person) super.clone();
person.setAddress(person.getAddress().clone());
return person;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
测试
Person person1 = new Person(new Address("武汉"));
Person person1Copy = person1.clone();
// false
System.out.println(person1.getAddress() == person1Copy.getAddress());
从输出结构来看,显然person1的克隆对象和person1包含的Address对象已经不同的了
引用拷贝
就是两个不同的引用指向同一个对象。
List a, list b; a=b 是浅拷贝还是深拷贝,怎么才能深拷贝?
属于引用拷贝,也就是两个不同的引用指向了同一个对象。即a和b指向了同一个List对象。当改变b时,a也会跟着改变。
List<String> a=new ArrayList<>();
a.add("aaa");
a.add("bbb");
List<String> b=new ArrayList<>();
b.add("ccc");
a=b;
System.out.println(a.hashCode()==b.hashCode());
b.add("ddddd");
System.out.println(a);
输出:
true
[ccc, ddddd]
如果想要深拷贝的话,需要重新创建一个新的List对象,并将原始列表中的元素复制到新列表。如果列表中的元素本身是对象的话,还要确保这些对象也被复制。
总结
浅拷贝会在堆上创建一个新的对象,不过如果原对象的内部属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。