对象的复制

Posted liufuyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对象的复制相关的知识,希望对你有一定的参考价值。

先放一段代码

Point.java

 1 public class Point {
 2     private int i;
 3  
 4     public Point(int i) {
 5         this.i = i;
 6     }
 7  
 8     public int getI() {
 9         return i;
10     }
11  
12     public void setI(int i) {
13         this.i = i;
14     }
15 }

 PointTest.java

 1 public class PointTest {
 2     public static void main(String[] args) {
 3         //创建一个Point对象,使用pa这个引用变量来指向它
 4         Point pa = new Point(5);
 5         //创建一个pb引用变量,将pa的值赋值给pb
 6         Point pb = pa;
 7         //改变pa中的属性的值
 8         pa.setI(3);
 9         //显示pb中的值
10         System.out.println(pb.getI());
11     }
12 }

输出的值为:3

因为pa和pb指向的是同一个对象(地址),改变其中任何一个都会改变该对象的内容。
那么如何做到分开呢?就是改变pa的时候不让pb发生改变(一般用于设置中间变量),这里就涉及到对象的复制。

浅拷贝

将Point类修改为Point2类:

 1 public class Point2 implements Cloneable {
 2     private int i;
 3  
 4     public Point2(int i) {
 5         this.i = i;
 6     }
 7  
 8     public int getI() {
 9         return i;
10     }
11  
12     public void setI(int i) {
13         this.i = i;
14     }
15  
16     @Override
17     public Object clone() throws CloneNotSupportedException {
18         return super.clone();
19     }
20 }

Point2Test.java

public class Point2Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一个Point2对象,使用p2a这个引用变量来指向它
        Point2 p2a = new Point2(5);
        //创建一个新对象,它是p2a的克隆,然后将这个新对象的引用赋值个p2b
        Point2 p2b = (Point2)p2a.clone();
        //改变p2a中的属性的值
        p2a.setI(3);
        //显示p2b中的值
        System.out.println(p2b.getI());
    }
}

输出的值为:5

p2a和p2b是内容相容的不同对象。
Object类中的clone方法将原始对象的每个数据域复制给目标对象:
1.如果一个数据域是基本类型,复制的就是它的值;
2.如果一个数据域是对象,那么复制的就是它的引用。注意这里是它的引用。
如果Point2类中有一个数据域Address类,那么虽然p2a==p2b为假,但是p2a.address==p2b.address为真。
所以这称之为浅拷贝。

深拷贝

Address类

 1 public class Address implements Cloneable {
 2     private String addressName;
 3  
 4     public String getAddressName() {
 5         return addressName;
 6     }
 7  
 8     public void setAddressName(String addressName) {
 9         this.addressName = addressName;
10     }
11  
12     @Override
13     public Object clone() throws CloneNotSupportedException {
14         return super.clone();
15     }
16 }

Point3类

 1 public class Point3 implements Cloneable {
 2     private int i;
 3     private Address address;
 4  
 5     public Point3(int i) {
 6         this.i = i;
 7     }
 8  
 9     public int getI() {
10         return i;
11     }
12  
13     public void setI(int i) {
14         this.i = i;
15     }
16  
17     public Address getAddress() {
18         return address;
19     }
20  
21     public void setAddress(Address address) {
22         this.address = address;
23     }
24  
25     @Override
26     public Object clone() throws CloneNotSupportedException {
27         Point3 p3 = null;
28         p3 = (Point3) super.clone();
29         p3.address = (Address) address.clone();
30  
31         return p3;
32     }
33 }

 

Point3Test.java

 1 public class Point3Test {
 2     public static void main(String[] args) throws CloneNotSupportedException {
 3         //初始化对象p3a
 4         Point3 p3a = new Point3(5);
 5         Address address = new Address();
 6         address.setAddressName("位置1");
 7         p3a.setAddress(address);
 8  
 9         //复制对象
10         Point3 p3b = (Point3) p3a.clone();
11  
12         //改变p3a的address
13         address.setAddressName("位置2");
14  
15         //输出结果比较
16         System.out.println("p3a的i: " + p3a.getI() + " p3a的address: " +
17             p3a.getAddress().getAddressName());
18         System.out.println("p3b的i: " + p3b.getI() + " p3b的address: " +
19             p3b.getAddress().getAddressName());
20     }
21 }

结果如图:

技术分享图片

结论:如果在拷贝一个对象时,要想让这个拷贝的对象和源对象完全彼此独立,那么在引用链上的每一级对象都要被显式的拷贝。所以创建彻底的深拷贝是非常麻烦的,尤其是在引用关系非常复杂的情况下。

所以有了如下一点,阿里巴巴Java开发手册第四章第19条:
【推荐】慎用 Object 的 clone 方法来拷贝对象。
说明: 对象的 clone 方法默认是浅拷贝,若想实现深拷贝需要重写 clone 方法实现属性对象的拷贝。

参考资料:
https://www.cnblogs.com/dolphin0520/p/3700693.html
https://blog.csdn.net/u014727260/article/details/55003402

本文系原创,转载请注明出处,谢谢。

以上是关于对象的复制的主要内容,如果未能解决你的问题,请参考以下文章

这两个代码片段之间有区别吗?如果有,那又如何? [复制]

什么是在 C++ 中获取总内核数量的跨平台代码片段? [复制]

Android:使用支持片段管理器时复制片段

VsCode 代码片段-提升研发效率

从图库中获取图像以在片段中的图像视图中设置? [复制]

VSCode自定义代码片段12——JavaScript的Promise对象