1.前言文案这个词想必大家都不陌生。工作中经常需要复印一份文件作为复印件。复制的好处也是显而易见的。与创建一个新的相比,它可以节省很多工作。在Java中,也存在拷贝的概念,拷贝的意义也是为了节省创建对象的开销。Object类中有一个方法clone()。具体方法如下:protectednativeObjectclone()throwsCloneNotSupportedException;该方法被protected修饰。java中的所有类默认都继承了Object类。重载后的clone()方法保证其他类可以正常调用,修饰符需要改为public。该方法为native方法,native修饰的方法实际上是非Java代码实现的,效率高于普通java方法。这个方法的返回值是一个Object对象,所以我们需要强制为我们需要的类型。此方法抛出CloneNotSupportedException,这意味着不支持复制。我们需要实现Cloneable接口来标记这个类支持复制。为了演示方便,我们新建两个实体类Dept和User,其中User依赖Dept,实体类代码如下:Dept类:@Data@AllArgsConstructor@NoArgsConstructorpublicclassDept{privateintdeptNo;privateStringname;}User类:@Data@AllArgsConstructor@NoArgsConstructorpublicclassUser{privateintage;privateStringname;privateDeptdept;}2.浅拷贝对于基本类型的属性,浅拷贝会将属性值拷贝到新对象中,对于引用类型的属性,浅拷贝会将引用拷贝到新对象。String和Integer等引用类型是不可变的。复制时,会创建一个新的内存空间来存放值,新的引用会指向新的内存空间。不可变类型是特殊的引用类型,我们假设这些最终标记的引用类型也是复制值。浅拷贝函数实现@Data@AllArgsConstructor@NoArgsConstructorpublicclassUserimplementsCloneable{privateintage;privateStringname;privateDeptdept;@OverrideprotectedObjectclone()throwsCloneNotSupportedException{returnsuper.clone();}}如何验证我们的结论?先比较复制出来的对象和原来的对象是否相等,不相等就说明是新复制的对象。其次,修改复制对象的基本类型属性。如果修改了原始对象的这个属性,则表示基本类型属性相同。最后,修改复制对象的引用类型对象,即Dept属性。如果原始对象的这个属性发生了变化,说明引用类型的属性是一样的。明确了测试原理后,我们编写测试代码来验证我们的结论。publicstaticvoidmain(String[]args)throwsException{Deptdept=newDept(12,"市场部");Useruser=newUser(18,"JavaJourney",dept);Useruser1=(User)user.clone();System.out.println(user==user1);System.out.println();user1.setAge(20);System.out.println(user);System.out.println(user1);System.out.println();dept.setName("研发部");System.out.println(user);System.out.println(user1);}上面代码的结果如下:falseUser{age=18,name='Java',dept=部门{deptNo=12,name='市场部'}}用户{age=20,name='Java',dept=部门{deptNo=12,name='市场部'}}用户{age=18,name='Java',dept=Dept{deptNo=12,name='研发部'}}User{age=20,name='Java',dept=Dept{deptNo=12,name='研发部'}}3、深拷贝与浅拷贝相比,深拷贝不仅拷贝了基本类型的属性,还拷贝了引用类型的属性。实现深拷贝功能,在复制用户的同时复制用户中的dept属性。部门类:@Data@AllArgsConstructor@NoArgsConstructorpublicclassDeptimplementsCloneable{privateintdeptNo;privateStringname;@OverridepublicObjectclone()throwsCloneNotSupportedException{returnsuper.clone();}}用户类:@Data@AllArgsConstructor@NoArgsConstructorpublicclassUserimplementsCloneable{privateintage;privateStringprotectedException()NotrideptedDept;@ateOverrideDeptedException;Useruser=(User)super.clone();user.dept=(Dept)dept.clone();returnuser;}}使用浅拷贝测试代码继续测试,运行结果如下:falseUser{age=18,name='Java之旅',dept=Dept{deptNo=12,name='市场部'}}User{age=20,name='Java之旅',dept=Dept{deptNo=12,name='市场部部门'}}用户{age=18,name='Java之旅',dept=部门{deptNo=12,name='研发部'}}用户{age=20,name='Java之旅',dept=部门{deptNo=12,name='MarketingDepartment'}}另外也可以使用反序列化实现深拷贝,先将对象序列化成bytestream,然后将字节流序列化为一个对象,会生成一个新的对象。本文转载自微信公众号“Java之旅”,可通过以下二维码关注。转载本文请联系Java之旅公众号。
