1. 主要区别
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是在复制对象或数据结构时所使用的两种不同的拷贝方法,它们之间的区别主要在于拷贝的程度和对原始对象内部结构的影响。
1.1 浅拷贝(Shallow Copy)
- 浅拷贝创建一个新的对象,但是只复制原始对象的基本数据类型的字段或引用(地址),而不复制引用指向的对象。这意味着新对象和原始对象中的引用指向相同的对象。
- 如果原始对象中的字段是基本数据类型,那么这些字段会被复制到新对象中,而如果字段是引用类型,则新对象和原始对- 象的对应字段将引用同一个对象。
- 因此,对新对象所做的修改可能会影响到原始对象,因为它们共享相同的引用。
1.2 深拷贝(Deep Copy)
- 深拷贝创建一个新的对象,并且递归地复制原始对象的所有字段和引用指向的对象,而不仅仅是复制引用本身。
- 深拷贝会递归复制整个对象结构,包括对象内部的对象,确保新对象和原始对象之间的所有关系都是独立的。
- 这意味着对新对象所做的修改不会影响到原始对象,因为它们拥有彼此独立的副本。
2. 浅拷贝示例代码
浅拷贝的示例代码如下,我们这里实现了 Cloneable 接口,并重写了 clone() 方法。clone() 方法的实现很简单,直接调用的是父类 Object 的 clone() 方法。
class Address {
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable {
private Address address;
public Person(Address address) {
this.address = address;
}
public Address getAddress() {
return address;
}
@Override
protected Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
}
在上面的代码中,Address 类实现了 Cloneable 接口,并重写了 clone() 方法,而 Person 类也实现了 Cloneable 接口并重写了 clone() 方法。
在 Address 类的 clone() 方法中,直接调用了父类 Object 的 clone() 方法。
在 Person 类的 clone() 方法中,也直接调用了父类 Object 的 clone() 方法。
接下来我们进行测试,测试代码如下:
public class Main {
public static void main(String[] args) {
try {
Person person1 = new Person(new Address("武汉"));
Person person1Copy = person1.clone();
// true
System.out.println(person1.getAddress() == person1Copy.getAddress());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
在这个测试中,我们期望输出 true,因为我们实现的是浅拷贝,所以新的 Person 对象和原始的 Person 对象引用的是相同的地址对象。
3. 深拷贝示例代码
这里我们简单对 Person 类的 clone() 方法进行修改,连带着要把 Person 对象内部的 Address 对象一起复制。
class Person implements Cloneable {
private Address address;
public Person(Address address) {
this.address = address;
}
public Address getAddress() {
return address;
}
@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.address = (Address) this.address.clone();
return person;
}
}
在这个修改后的 clone() 方法中,我们首先调用了父类的 clone() 方法创建了一个新的 Person 对象,然后将当前对象的 address 成员变量也进行了克隆,并将克隆后的地址对象赋给新创建的 Person 对象。
接下来,我们来测试一下深拷贝的效果:
public class Main {
public static void main(String[] args) {
try {
Person person1 = new Person(new Address("武汉"));
Person person1Copy = person1.clone();
// false
System.out.println(person1.getAddress() == person1Copy.getAddress());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
在这个测试中,我们期望输出 false,因为我们实现了深拷贝,所以新的 Person 对象和原始的 Person 对象引用的是不同的地址对象。