java中深复制与浅复制的区别是什么
Java中的深复制(Deep Copy)和浅复制(Shallow Copy)是非常重要的概念,其中深复制是复制一个对象的所有内容,包括对象的引用类型,而浅复制仅仅是复制对象本身,不涉及到对象的引用类型。在这篇文章中,我将详细讨论Java中深复制与浅复制的区别。
深复制(Deep Copy)
在Java中,如果我们想要复制一个对象的所有内容,包括对象内容和引用类型,那么就需要使用深复制。在深复制中,对象及其所有引用类型都会被复制到一个新的对象中,因此,新的对象与原始对象是完全独立的。这意味着,如果我们在新对象中修改一个引用类型的值,那么原始对象不会受到任何影响。
让我们考虑以下示例代码:
public class Student implements Cloneable {
private String name;
private int age;
private Department department;
public Student(String name, int age, Department department) {
this.name = name;
this.age = age;
this.department = department;
}
public void setDepartment(Department department) {
this.department = department;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Department getDepartment() {
return department;
}
@Override
public Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.department = (Department) department.clone();
return student;
}
}
public class Department implements Cloneable {
private String name;
public Department(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
在上面的示例中,我们有一个学生类,其中包括学生的名字、年龄和一个Department对象。我们还有一个Department类,其中包括名称。
要将Student类进行深复制,我们需要使其实现Cloneable接口并重写clone方法。在clone方法中,我们创建一个Student对象,并将其字段复制到新对象中。由于Department类中也有一个引用类型,我们需要在Student类的clone方法中调用Department类的clone方法来完成深复制。在Department类的clone方法中,我们只需使用Object类的clone方法,因为它只包含基本类型。
让我们测试一下:
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Department department = new Department("Software Engineering");
Student student1 = new Student("Alice", 20, department);
Student student2 = (Student) student1.clone();
System.out.println("student1: " + student1.getName() + " " + student1.getAge() + " " + student1.getDepartment().getName());
System.out.println("student2: " + student2.getName() + " " + student2.getAge() + " " + student2.getDepartment().getName());
student2.getDepartment().setName("Computer Science");
System.out.println("student1: " + student1.getName() + " " + student1.getAge() + " " + student1.getDepartment().getName());
System.out.println("student2: " + student2.getName() + " " + student2.getAge() + " " + student2.getDepartment().getName());
}
}
输出结果:
student1: Alice 20 Software Engineering
student2: Alice 20 Software Engineering
student1: Alice 20 Software Engineering
student2: Alice 20 Computer Science
在上面的示例中,我们创建了两个学生对象,并将它们存储在student1和student2变量中。然后,我们修改了student2的部门名称,并输出了student1和student2的详细信息。在输出中,我们可以看到如果我们修改一个引用类型的值,那么原始对象不会受到任何影响。
浅复制(Shallow Copy)
浅复制是仅仅复制对象本身,不涉及到对象的引用类型。在Java中,我们可以使用Object类中的clone方法来执行浅复制。
让我们考虑以下示例代码:
public class Student implements Cloneable {
private String name;
private int age;
private Department department;
public Student(String name, int age, Department department) {
this.name = name;
this.age = age;
this.department = department;
}
public void setDepartment(Department department) {
this.department = department;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Department getDepartment() {
return department;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Department {
private String name;
public Department(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
在上面的示例中,我们仍然有一个学生类,其中包括学生的名字、年龄和一个Department对象。我们在Department类中不需要实现Cloneable接口,因为它只包含基本类型。
要将Student类进行浅复制,我们需要使其实现Cloneable接口并重写clone方法。在clone方法中,我们只需调用super.clone方法,因为这个方法已经复制了Student对象。但是,由于我们在Student类中有一个引用类型,所以复制的只是这个引用类型的对象地址,这意味着新对象和原始对象共享同一个Department对象。因此,如果我们在新对象中修改引用类型的值,原始对象也会受到影响。
让我们测试一下:
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Department department = new Department("Software Engineering");
Student student1 = new Student("Alice", 20, department);
Student student2 = (Student) student1.clone();
System.out.println("student1: " + student1.getName() + " " + student1.getAge() + " " + student1.getDepartment().getName());
System.out.println("student2: " + student2.getName() + " " + student2.getAge() + " " + student2.getDepartment().getName());
student2.getDepartment().setName("Computer Science");
System.out.println("student1: " + student1.getName() + " " + student1.getAge() + " " + student1.getDepartment().getName());
System.out.println("student2: " + student2.getName() + " " + student2.getAge() + " " + student2.getDepartment().getName());
}
}
输出结果:
student1: Alice 20 Software Engineering
student2: Alice 20 Software Engineering
student1: Alice 20 Computer Science
student2: Alice 20 Computer Science
在上面的示例中,我们创建了两个学生对象,并将它们存储在student1和student2变量中。然后,我们修改了student2的部门名称,并输出了student1和student2的详细信息。在输出中,我们可以看到如果我们修改一个引用类型的值,那么原始对象也会受到影响。
总结
在Java中,深复制和浅复制都是非常重要的概念。在深复制中,我们复制对象及其所有引用的类型,而在浅复制中,我们仅仅复制对象本身,不涉及到对象的引用类型。因此,在使用clone方法时要非常小心,需要根据具体情况选用深复制或浅复制。
在实际开发中,如果我们需要复制一个对象及其所有的引用类型,那么我们应该使用深复制。相反,如果我们只需要复制一个对象本身,那么我们应该使用浅复制。在复制对象时,我们需要确保对象及其所有引用类型都正确地执行了clone方法,以避免出现错误。
