什么是浅拷贝和深拷贝?
- 浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;
- 深拷贝:复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变;
浅拷贝
拷贝对象和原始对象的引用类型引用同一个对象。
@Test
public void copyDemo1(){
User user1 = new User(1,"baili", "baili.com");
User user2 = user1; // 浅拷贝
System.out.println("User 1: " + user1);
System.out.println("User 2: " + user2);
// 分别修改user对象的属性
user1.setUsername("百里");
user2.setEmail("百里.com");
// 输出修改后的结果
System.out.println("User 1: " + user1);
System.out.println("User 2: " + user2);
}
深拷贝
拷贝对象和原始对象的引用类型引用不同对象。
package polo;
import java.util.ArrayList;
import java.util.List;
/**
* @author 百里
*/
public class Person implements Cloneable {
private string name;
private int age;
private List<String> hobbies;
public Person(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
// Getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
@Override
public Person clone() throws CloneNotSupportedException {
// 浅拷贝对象
Person clonedPerson = (Person) super.clone();
// 深拷贝 List
clonedPerson.setHobbies(new ArrayList<>(hobbies));
return clonedPerson;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", hobbies=" + hobbies + "]";
}
}
@Test
public void copyDemo2(){
List<String> hobbies = new ArrayList<>();
hobbies.add("Reading");
hobbies.add("Gardening");
Person person1 = new Person("baili", 30, hobbies);
try {
Person person2 = person1.clone(); // 深拷贝
System.out.println("Person 1: " + person1);
System.out.println("Person 2: " + person2);
// 修改 person2 的属性
person2.setName("百里");
person2.setAge(25);
person2.getHobbies().add("Cooking");
// 输出修改后的结果
System.out.println("Person 1: " + person1);
System.out.println("Person 2: " + person2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
使用拷贝构造函数:
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 拷贝构造函数
public Person(Person other) {
this.name = other.name;
this.age = other.age;
}
// Getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person("baili", 30);
// 使用拷贝构造函数创建 person2 对象
Person person2 = new Person(person1);
System.out.println("Person 1: " + person1);
System.out.println("Person 2: " + person2);
// 修改 person2 的属性
person2.setName("BAILI");
person2.setAge(25);
// 输出修改后的结果
System.out.println("Person 1: " + person1);
System.out.println("Person 2: " + person2);
}
}
使用拷贝工厂:
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
class PersonFactory {
public static Person createCopy(Person original) {
// 使用拷贝构造函数创建新的对象
return new Person(original.getName(), original.getAge());
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person("bali", 30);
// 使用拷贝工厂创建 person2 对象
Person person2 = PersonFactory.createCopy(person1);
System.out.println("Person 1: " + person1);
System.out.println("Person 2: " + person2);
// 修改 person2 的属性
person2.setName("BAILI");
person2.setAge(25);
// 输出修改后的结果
System.out.println("Person 1: " + person1);
System.out.println("Person 2: " + person2);
}
}