对象拷贝


对象拷贝就是将一个对象的属性拷贝到另一个有着相同属性类类型的对象中去。
主要是为了在新的上下文环境中复用对象的部分或全部数据。 java中有三种类型的对象拷贝:浅拷贝、深拷贝、延迟拷贝

一、浅拷贝

什么是浅拷贝?

浅拷贝就是按位拷贝,他会创建一个新对象,这个对象有着原始对象属性值的一份精准拷贝。属性是基本类型,拷贝的就是基本类型的值;属性是内存地址(引用类型),拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。


public class Student implements Cloneable {
    private String name;
    CopySubject copySubject;

    public Student(String name, String copy) {
        this.name = name;
        this.copySubject = new CopySubject(copy);
    }

    public CopySubject getCopySubject() {
        return copySubject;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object clone() throws CloneNotSupportedException {
        //浅拷贝
        try {
            // 直接调用父类的clone()方法
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

public class CopySubject {
    private String name;

    public CopySubject(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}



public class CloneSubject {
    public static void main(String[] args) {
        Student student = new Student("当前同学", "拷贝同学");
        System.out.println("Original Object:" + student.getName() + "---" + student.getCopySubject().getName());

        try {
            Student cloneObject = (Student) student.clone();
            System.out.println("Cloned Object:" + cloneObject.getName() + "---" + cloneObject.getCopySubject().getName());

            System.out.println("Is Original Object the same with Cloned Object " + (cloneObject == student));

            System.out.println("Is Original Object is field the same with Cloned Object is field " +
                    (cloneObject.getCopySubject() == student.getCopySubject()));

            System.out.println("Is Original Object is field the same with Cloned Object is field " +
                    (cloneObject.getName() == student.getName()));

            student.setName("设置当前同学");
            student.getCopySubject().setName("设置拷贝同学");
            System.out.println("Original Object after it is updated:" + student.getName() +
                    "--" + student.getCopySubject().getName());

            System.out.println("Cloned Object after it is update:" + cloneObject.getName()
                    + "---" + cloneObject.getCopySubject().getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

输出结果

Original Object:当前同学---拷贝同学
Cloned Object:当前同学---拷贝同学
Is Original Object the same with Cloned Object false
Is Original Object is field the same with Cloned Object is field true
Is Original Object is field the same with Cloned Object is field true
Original Object after it is updated:设置当前同学--设置拷贝同学
Cloned Object after it is update:当前同学---设置拷贝同学

结论:
Student 继承 接口 Cloneable 重写 clone() 方法。
从输出结果看 Original Object(原始对象)数据Cloned Object(克隆对象)数据一样,但是原始对象地址与克隆地址不一样,但是与克隆属性对象地址一样。
修改原始数据后,原始数据发生改变,克隆数据没有发生改变,但是克隆对象数据发生改变。

二、深拷贝

1.什么是深拷贝?

深拷贝会拷贝所有的属性,并拷贝属性指向动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比浅拷贝速度较慢并且花销较大。

public class DeepCopyStudent implements Cloneable{
    private String name;
    private CopySubject copySubject ;

    public DeepCopyStudent(String name, String copy) {
        this.name = name;
        this.copySubject = new CopySubject(copy);
    }

    public CopySubject getCopySubject() {
        return copySubject;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Object clone() throws CloneNotSupportedException {
        DeepCopyStudent student = new DeepCopyStudent(name,copySubject.getName());
        return student;
    }
}
public class CloneSubject {
    public static void main(String[] args) {
        DeepCopyStudent student = new DeepCopyStudent("当前同学", "拷贝同学");
        System.out.println("Original Object:" + student.getName() + "---" + student.getCopySubject().getName());

        try {
            DeepCopyStudent cloneObject = (DeepCopyStudent) student.clone();
            System.out.println("Cloned Object:" + cloneObject.getName() + "---" + cloneObject.getCopySubject().getName());

            System.out.println("Is Original Object the same with Cloned Object " + (cloneObject == student));

            System.out.println("Is Original Object is field the same with Cloned Object is field " +
                    (cloneObject.getCopySubject() == student.getCopySubject()));

            System.out.println("Is Original Object is field the same with Cloned Object is field " +
                    (cloneObject.getName() == student.getName()));

            student.setName("设置当前同学");
            student.getCopySubject().setName("设置拷贝同学");
            System.out.println("Original Object after it is updated:" + student.getName() +
                    "--" + student.getCopySubject().getName());

            System.out.println("Cloned Object after it is update:" + cloneObject.getName()
                    + "---" + cloneObject.getCopySubject().getName());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

输出结果

Original Object:当前同学---拷贝同学
Cloned Object:当前同学---拷贝同学
Is Original Object the same with Cloned Object false
Is Original Object is field the same with Cloned Object is field false
Is Original Object is field the same with Cloned Object is field true
Original Object after it is updated:设置当前同学--设置拷贝同学
Cloned Object after it is update:当前同学---拷贝同学

结果:
Student 继承 接口 Cloneable 重写 **clone()**方法。
从输出结果看 Original Object(原始对象)数据Cloned Object(克隆对象)数据一样,原始对象与克隆对象不一样,原始对象属性与克隆对象属性不一样,设置原对象数据,原对象数据元素有修改。但是克隆对象没有修改。

2.通过序列化实现深拷贝

序列化是干什么的?
它将整个对象图写入到一个持久化存储文件中并且当需要的时候把它读取回来,
这意味着当你需要把它读取回来时你需要整个对象图的一个拷贝。
import java.io.Serializable;

public class ColoredCircle implements Serializable {
    private int X;
    private int Y;

    public ColoredCircle(int x, int y) {
        X = x;
        Y = y;
    }

    public int getX() {
        return X;
    }

    public void setX(int x) {
        X = x;
    }

    public int getY() {
        return Y;
    }

    public void setY(int y) {
        Y = y;
    }

    @Override
    public String toString() {
        return "ColoredCircle{" +
                "X=" + X +
                ", Y=" + Y +
                '}';
    }
}

import java.io.*;

public class SerializableDeepCopy {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        ColoredCircle circle = new ColoredCircle(100, 100);
        System.out.println("Original Object " + circle);

        //通过序列化实现深拷贝
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            oos = new ObjectOutputStream(baos);
            //序列化以及传递这个对象
            oos.writeObject(circle);
            oos.flush();

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ois = new ObjectInputStream(bais);
            ColoredCircle readObject = (ColoredCircle) ois.readObject();
            System.out.println("Copied =" + readObject);

            readObject.setX(200);
            readObject.setY(200);

            System.out.println("Original Object =" + circle + "\n Cloned Object = " + readObject);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


输出结果

Original Object ColoredCircle{X=100, Y=100}
Copied =ColoredCircle{X=100, Y=100}
Original Object =ColoredCircle{X=200, Y=200}
Cloned Object = ColoredCircle{X=100, Y=100}
  • 确保对象图中的所有类都是可序列化的
  • 创建输入输出流
  • 使用输入输出流来创建输入和对象输出流
  • 将你想要拷贝的对象传递给对象输出流
  • 从对象输入流中读取新的对象并且转换回你所发送的对象的类。

延迟拷贝

1. 什么是延迟拷贝?

延迟拷贝是浅拷贝和深拷贝的一个组合。当最开始拷贝一个对象时,会使用速度较快的浅拷贝,还会使用一个计数器来记录有多少对象共享这个数据,当程序想要修改原始的对象时,它会决定数据是否被共享并根据需要进行深拷贝。

延迟拷贝从外面看起来就是深拷贝,但是只要有可能他就会利用浅拷贝的速度。当原始对象中,引用不经常改变的时候可以使用延迟拷贝。由于存在计数器,效率很高,但只是常量级的开销。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值