前言 对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部数据。
浅拷贝 浅拷贝(Shallow Copy)只拷贝指向某个对象的指针(内存地址),而不拷贝对象本身,新旧对象还是共享同一块内存,类似一个分支。
拷贝基本类型拷贝的就是基本类型(如 int
、float
)的值。 拷贝引用类型拷贝的就是内存地址,相当于多个引用指向同一个对象,因此如果其中一个对象改变了这个内存地址的内容,就会影响到另一个对象。
深拷贝 深拷贝(Deep Copy)会另外创建一个一模一样的拷贝对象,这个拷贝对象跟原对象不共享内存,修改拷贝对象不会对原对象产生任何影响。深拷贝是拷贝了原对象的所有值,所以即使原对象的值发生了变化,拷贝对象的值也不会改变。
为什么需要深拷贝呢?
避免共享引用当拷贝一个对象时,如果不使用深拷贝,那么拷贝的实际上是对原对象的引用,而不是真正的副本。这意味着对副本的任何修改都会影响到原对象。深拷贝则能确保拷贝的是对象的真正副本,与原对象没有引用关系。 保证线程安全在多线程环境中,如果多个线程同时访问和修改同一个对象,可能会导致数据不一致和竞态条件。通过深拷贝创建对象的副本,每个线程都可以在自己的副本上进行操作,从而避免了线程安全问题。 Cloneable 接口 1 2 3 public interface Cloneable {}
1 2 3 4 5 6 7 public class Object { @HotSpotIntrinsicCandidate protected native Object clone () throws CloneNotSupportedException ; ...... }
如果某个类没有实现 Cloneable 接口就直接调用 clone()
方法,则会抛出 CloneNotSupportedException
异常 1 2 3 4 5 6 7 8 public class ObjectCopyDemo { public static void main (String[] args) throws Exception { ObjectCopyDemo demo = new ObjectCopyDemo(); Object clone = demo.clone(); } }
1 2 3 Exception in thread "main" java.lang.CloneNotSupportedException: com.java.interview.base.ObjectCopyDemo at java.base/java.lang.Object.clone(Native Method) at com.java.interview.base.ObjectCopyDemo.main(ObjectCopyDemo.java:7)
浅拷贝的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class ShallowCopyDemo { public static void main (String[] args) throws Exception { Emp emp = new Emp("z3" , 15 , "雷军" , "CEO" ); System.out.println("原始对象:" + emp.getBoss().getTitle()); Emp emp2 = (Emp) emp.clone(); System.out.println("拷贝对象:" + emp2.getBoss().getTitle()); emp2.getBoss().setTitle("CTO" ); System.out.println("------拷贝对象修改 title 为 CTO,是否会影响原始对象" ); System.out.println("原始对象:" + emp.getBoss().getTitle()); System.out.println("拷贝对象:" + emp2.getBoss().getTitle()); } @Data @AllArgsConstructor @NoArgsConstructor private static class Boss implements Cloneable { private String bossName; private String title; @Override protected Object clone () throws CloneNotSupportedException { return super .clone(); } } @Data @AllArgsConstructor @NoArgsConstructor private static class Emp implements Cloneable { private String empName; private Integer age; private Boss boss; public Emp (String empName, Integer age, String bossName, String title) { this .empName = empName; this .age = age; this .boss = new Boss(bossName, title); } @Override protected Object clone () throws CloneNotSupportedException { return super .clone(); } } }
程序运行的输出结果为:
1 2 3 4 5 原始对象:CEO 拷贝对象:CEO ------拷贝对象修改 title 为 CTO,是否会影响原始对象 原始对象:CTO 拷贝对象:CTO
深拷贝的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class DeepCopyDemo { public static void main (String[] args) throws Exception { Emp emp = new Emp("z3" , 15 , "雷军" , "CEO" ); System.out.println("原始对象:" + emp.getBoss().getTitle()); Emp emp2 = (Emp) emp.clone(); System.out.println("拷贝对象:" + emp2.getBoss().getTitle()); emp2.getBoss().setTitle("CTO" ); System.out.println("------拷贝对象修改 title 为 CTO,是否会影响原始对象" ); System.out.println("原始对象:" + emp.getBoss().getTitle()); System.out.println("拷贝对象:" + emp2.getBoss().getTitle()); } @Data @AllArgsConstructor @NoArgsConstructor private static class Boss implements Cloneable { private String bossName; private String title; @Override protected Object clone () throws CloneNotSupportedException { return super .clone(); } } @Data @AllArgsConstructor @NoArgsConstructor private static class Emp implements Cloneable { private String empName; private Integer age; private Boss boss; public Emp (String empName, Integer age, String bossName, String title) { this .empName = empName; this .age = age; this .boss = new Boss(bossName, title); } @Override protected Object clone () throws CloneNotSupportedException { return new Emp(empName, age, boss.getBossName(), boss.getTitle()); } } }
程序运行的输出结果为:
1 2 3 4 5 原始对象:CEO 拷贝对象:CEO ------拷贝对象修改 title 为 CTO,是否会影响原始对象 原始对象:CEO 拷贝对象:CTO