深拷贝和浅拷贝是面试常考问题。本文通过图解和代码示例,彻底搞清楚它们的区别以及如何正确实现深拷贝。
概念区分 浅拷贝(Shallow Copy) 创建一个新对象,但新对象的字段直接复制 原对象字段的值:
基本类型:复制值本身
引用类型:复制引用地址(指向同一个对象)
深拷贝(Deep Copy) 创建一个新对象,并且递归复制 所有引用类型字段指向的对象,使新旧对象完全独立。
图解区别 假设有一个 Person 对象,包含一个 Address 引用:
1 2 3 4 5 6 原对象 person1: ┌─────────────┐ ┌─────────────┐ │ name: "Tom" │ │ city: "北京" │ │ age: 25 │──────▶│ street: "X" │ │ address ────│ └─────────────┘ └─────────────┘ Address对象
浅拷贝后 1 2 3 4 5 6 7 8 9 10 11 12 13 person1: ┌─────────────┐ ┌─────────────┐ │ name: "Tom" │ │ city: "北京" │ │ age: 25 │──┬───▶│ street: "X" │ │ address ────│ │ └─────────────┘ └─────────────┘ │ 同一个Address! │ person2: │ ┌─────────────┐ │ │ name: "Tom" │ │ │ age: 25 │──┘ │ address ────│ └─────────────┘
修改 person2.address.city 会影响 person1!
深拷贝后 1 2 3 4 5 6 7 8 9 10 11 12 13 person1: ┌─────────────┐ ┌─────────────┐ │ name: "Tom" │ │ city: "北京" │ │ age: 25 │──────▶│ street: "X" │ │ address ────│ └─────────────┘ └─────────────┘ Address对象1 person2: ┌─────────────┐ ┌─────────────┐ │ name: "Tom" │ │ city: "北京" │ │ age: 25 │──────▶│ street: "X" │ │ address ────│ └─────────────┘ └─────────────┘ Address对象2(独立的)
两个对象完全独立,互不影响。
代码示例 定义类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Address { String city; String street; Address(String city, String street) { this .city = city; this .street = street; } } class Person implements Cloneable { String name; int age; Address address; Person(String name, int age, Address address) { this .name = name; this .age = age; this .address = address; } }
浅拷贝实现 1 2 3 4 @Override protected Person clone () throws CloneNotSupportedException { return (Person) super .clone(); }
验证浅拷贝的问题:
1 2 3 4 5 6 7 8 Person p1 = new Person ("Tom" , 25 , new Address ("北京" , "长安街" ));Person p2 = p1.clone();p2.name = "Jerry" ; p2.address.city = "上海" ; System.out.println(p1.name); System.out.println(p1.address.city);
深拷贝实现 方法1:手动递归拷贝 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Address implements Cloneable { @Override protected Address clone () throws CloneNotSupportedException { return (Address) super .clone(); } } class Person implements Cloneable { @Override protected Person clone () throws CloneNotSupportedException { Person cloned = (Person) super .clone(); cloned.address = this .address.clone(); return cloned; } }
方法2:序列化反序列化 1 2 3 4 5 6 7 8 9 10 11 12 13 public Person deepClone () { try { ByteArrayOutputStream bos = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (bos); oos.writeObject(this ); ByteArrayInputStream bis = new ByteArrayInputStream (bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream (bis); return (Person) ois.readObject(); } catch (Exception e) { throw new RuntimeException (e); } }
注意:所有相关类必须实现 Serializable 接口。
方法3:JSON序列化 1 2 3 4 5 6 7 8 9 10 public Person deepClone () { ObjectMapper mapper = new ObjectMapper (); try { String json = mapper.writeValueAsString(this ); return mapper.readValue(json, Person.class); } catch (Exception e) { throw new RuntimeException (e); } }
方法4:拷贝构造函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Person { public Person (Person other) { this .name = other.name; this .age = other.age; this .address = new Address (other.address); } } class Address { public Address (Address other) { this .city = other.city; this .street = other.street; } }
各种类型的拷贝行为
类型
浅拷贝行为
需要深拷贝?
基本类型 (int, double等)
复制值
不需要
String
复制引用,但String不可变,安全
不需要
数组
复制引用
需要
集合 (List, Map等)
复制引用
需要
自定义对象
复制引用
需要
数组的深拷贝 1 2 3 4 5 int [] arr1 = {1 , 2 , 3 };int [] arr2 = arr1.clone(); Person[] arr3 = {new Person (...)}; Person[] arr4 = arr3.clone();
集合的深拷贝 1 2 3 4 5 6 7 8 9 10 List<Person> list1 = new ArrayList <>(); list1.add(new Person ("Tom" , 25 , new Address ("北京" , "X" ))); List<Person> list2 = new ArrayList <>(list1); List<Person> list3 = list1.stream() .map(Person::clone) .collect(Collectors.toList());
总结
特性
浅拷贝
深拷贝
基本类型字段
独立
独立
引用类型字段
共享
独立
实现复杂度
简单
复杂
性能
快
慢
使用场景
对象只有基本类型字段
需要完全独立的副本
选择建议:
如果对象只包含基本类型和不可变对象(如String),浅拷贝足够
如果对象包含可变引用类型,且需要独立修改,使用深拷贝
推荐使用拷贝构造函数,代码清晰且类型安全