> 文章列表 > Java面试必备:深拷贝、浅拷贝、引用拷贝的区别

Java面试必备:深拷贝、浅拷贝、引用拷贝的区别

Java面试必备:深拷贝、浅拷贝、引用拷贝的区别

Java中的拷贝可以分为深拷贝(Deep Copy)、浅拷贝(Shallow Copy)和引用拷贝(Reference Copy)。它们之间的区别如下:

浅拷贝:

只复制对象本身,而不复制对象包含的子对象。新旧对象之间共享子对象的引用,即新对象和原始对象中的子对象指向同一个内存地址。

浅拷贝:使用clone()方法或者Object类的copy()方法。

深拷贝:

不仅复制对象本身,还要复制对象包含的所有子对象。新对象和原始对象所包含的子对象是相互独立的。

深拷贝:可以通过序列化和反序列化、递归遍历等方式来实现。

引用拷贝:

只复制对象的引用,而不复制对象本身。新旧对象之间共享同一个对象实例,即它们的引用指向同一个内存地址。

引用拷贝:直接将对象的引用赋值给另一个变量即可。

例如,以下代码演示了引用拷贝和浅拷贝的区别:

class Person {public String name;public int age;
}public class CopyDemo {public static void main(String[] args) {Person p1 = new Person();p1.name = "Alice";p1.age = 20;Person p2 = p1; // 引用拷贝System.out.println(p1 == p2);         // true, 引用相等System.out.println(p1.name == p2.name); // true, 字符串常量池中的引用相同System.out.println(p1.age == p2.age);   // true, 基本数据类型的值相同Person p3 = (Person)p1.clone(); // 浅拷贝System.out.println(p1 == p3);         // false, 引用不相等System.out.println(p1.name == p3.name); // true, 字符串常量池中的引用相同System.out.println(p1.age == p3.age);   // true, 基本数据类型的值相同}
}

在上面的代码中,p1和p2是两个对象的引用,它们指向同一个对象实例。在使用引用拷贝时,p2和p1共享同一个对象实例,所以它们的属性值相等,并且两个引用也是相等的。

而当使用浅拷贝时,p3是通过调用p1的clone()方法来复制p1的对象的。由于这种方式只是复制了对象本身,而没有复制对象包含的子对象,所以p1和p3引用不同的对象实例。但由于name属性的值是字符串常量,字符串常量池中只有一个实例,所以p1和p3的name属性指向同一个对象。但age是一个基本数据类型,不是一个对象,所以p1和p3的age属性值相等。

例如,以下代码演示了深拷贝和浅拷贝的区别:

public class Address implements Cloneable {private String name;  @Overridepublic Address clone() {try {return (Address) super.clone();} catch (CloneNotSupportedException e) {throw new AssertionError();}}
}public class Person implements Cloneable {public String name;public int age;private Address address;// 省略构造函数、Getter&Setter方法     @Overridepublic 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 对象。

深拷贝

这里我们简单对 Person 类的 clone() 方法进行修改,连带着要把 Person 对象内部的 Address 对象一起复制。

@Overridepublic 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 对象已经是不同的了。

七大队汽车俱乐部