【JAVA】浅拷贝和深拷贝

等号赋值

在 Java 中,除了基本数据类型(数值)之外,还存在 类的实例对象 这个引用数据类型。而一般使用“ = ”号做赋值操作的时候,对于基本数据类型,拷贝的它的值。对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向的同一个对象

下面来看例子:


输出对应的信息:


直接使用等号=进行赋值操作,可以看出两个对象的hashcode码是相同的,代表他们指向同一个对象的地址,改变其中一个对象的属性值,另一个对象的值也会跟着改变


浅拷贝和深拷贝

浅拷贝和深拷贝就是在这个基础之上做的区分

对基本数据类型进行拷贝,对引用数据类型进行引用传递,没有创建一个新的对象,则认为是浅拷贝。

反之,对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝

浅拷贝

JAVA中的所有类都继承自Object类,在Object类中存在一个clone()方法,被声明为protect(只允许在子类中调用)。

只要子类实现了Cloneable()接口,就可以直接调用该方法。clone()方法可以在拷贝过程中生成一个新的对象实例,实现浅拷贝操作


下面来看例子:


运行结果:


直接通过实现父类的clone()方法就可以实现对象的浅拷贝,从hashcode可以看出,拷贝过程生成了两个不同的对象

但是!

问题出在了这一行


我们在Father类中新建了一个Child实例作为该类的成员,那么在执行同样的浅拷贝操作之后,会生成两个不同的父类+两个不同的子类吗?


不会! 通过hashcode可以看出,拷贝生成了两个不同的父类,但是子类依然指向了同一个对象的地址,这就是”浅拷贝“名称的由来,只能进行浅层(一层)对象的拷贝。那么什么是深拷贝呢?

深拷贝

两种方法:1、重写子类对象的Clone()方法实现深拷贝2、使用序列化和反序列化进行深拷贝操作


1、重写子类对象的Clone()方法实现深拷贝


简单来说就是对Father类中的child子类 ,再进行了一次 clone() 操作

对于Child()子类来说,这是一次浅拷贝,但是对于Father()类来说,就是一次深拷贝

输出结果:



2、使用序列化和反序列化进行深拷贝操作

把对象写到流里的过程是序列化过程(Serialization),而把对象从流中读出来的过程则叫做反序列化过程(Deserialization)

在Java中实现深拷贝操作,首先先实现Serializable接口,然后把对象写到一个字节流里,再从字节流里读出来,便可以重建对象。该新对象与旧对象之间并不存在引用共享的问题,从而真正实现了对象的深拷贝




来看运行结果:


通过hashCode可以看到该操作生成了不同的父类和子类,的确实现了深拷贝

对于更深层次的子类,只要在最外层父类中实现序列化和反序列化操作,并在每一层的子类中实现serializable接口,就可以方便地完成深拷贝操作!

By the way,代码中还进行了子类的Name属性修改操作,所以会生成不同的名字


附测试代码:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class CloneTest3 {
    // 通过序列化的方式实现对象的深拷贝
    public static void main(String[] args) throws Exception {
        Father f1 = new Father();
        f1.setName("张三");
        f1.child.setName("张小三");
        //Father f2 =f1;

        //Father f2 = (Father) f1.clone();//实现Cloneable接口实现浅拷贝&重写子类对象的Cloneable接口实现深拷贝
        Father f2 = (Father) f1.deepClone();//使用序列化和反序列化进行深拷贝操作

        // 将复制后的对象信息修改一下
        f2.setName("李四");

        System.out.println("原来对象的姓名:" + f1.getName());
        System.out.println("原来对象的hashCode:" + f1.hashCode());
        System.out.println("拷贝对象的姓名:" + f2.getName());
        System.out.println("拷贝对象的hashCode:" + f2.hashCode());

        // 将复制后的对象的孩子信息修改一下
        f2.child.setName("李小四");

        System.out.println("原来对象的孩子姓名:" + f1.child.getName());
        System.out.println("原来对象的孩子hashCode:" + f1.child.hashCode());
        System.out.println("拷贝对象的孩子姓名:" + f2.child.getName());
        System.out.println("拷贝对象的孩子hashCode:" + f2.child.hashCode());
    }
}

///*****************Cloneable接口实现浅拷贝*****************/
//class Father implements Cloneable{//实现Cloneable接口
//    public String name;
//    public Child child = new Child();
//
//    public String getName() {
//        return name;
//    }
//
//    public void setName(String name) {
//        this.name = name;
//    }
//
//    public Object clone(){
//        try{
//            //浅拷贝
//            return super.clone();
//        } catch (CloneNotSupportedException ignore){
//        }
//        return null;
//    }
//}
//
//class Child implements Cloneable {
//    private String name;
//
//    public String getName() {
//        return name;
//    }
//
//    public void setName(String name) {
//        this.name = name;
//    }
//}

///*****************重写子类对象的Cloneable接口实现深拷贝*****************/
//class Father implements Cloneable{
//    public String name;
//    public Child child = new Child();
//
//    public String getName()
//    {
//        return name;
//    }
//
//    public void setName(String name)
//    {
//        this.name = name;
//    }
//
//    public Object clone(){
//        try{
//            //深拷贝
//            Father cloneFather = (Father) super.clone();
//            cloneFather.child = (Child) this.child.clone();
//            return cloneFather;
//        } catch (CloneNotSupportedException ignore){
//        }
//        return null;
//    }
//}
//
//class Child implements Cloneable {
//    private String name;
//
//    public String getName() {
//        return name;
//    }
//
//    public void setName(String name) {
//        this.name = name;
//    }
//
//    public Object clone(){
//        try{
//            //重写clone()方法是实现深拷贝
//            return super.clone();
//        } catch (CloneNotSupportedException ignore){
//        }
//        return null;
//    }
//}

/*****************使用序列化和反序列化进行深拷贝操作*****************/
class Father implements Serializable
{
    private String name;
    public Child child = new Child();//在Father类中,还有一个Child类的对象child

    public String getName() {
        return name;
    }

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

    public Object deepClone() throws Exception {
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeObject(this);

        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);

        return ois.readObject();
    }
}

class Child implements Serializable
{
        private String name;
        public String getName() {
        return name;
    }

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值