美文网首页
Java基础 - 深拷贝和浅拷贝

Java基础 - 深拷贝和浅拷贝

作者: z嘉嘉嘉 | 来源:发表于2019-01-29 14:14 被阅读0次

Java 的深拷贝和浅拷贝

什么是深拷贝、浅拷贝 (深克隆、浅克隆)?

在 Java 中,数据类型分为 基本数据类型引用数据类型,深/浅拷贝是针对于 引用数据类型 来说的。

  • 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝称为浅拷贝。通过实现Cloneable接口并重写Object类中的clone()方法可以实现浅克隆。

    浅拷贝.png
  • 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容称为深拷贝。

    深拷贝.png

如何进行深拷贝?

  • 实现Cloneable接口并重写Object类及成员变量中引用类型的的clone()方法
  • 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

注意:基于序列化和反序列化实现的拷贝不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

举个栗子

实现Cloneable接口 : 浅克隆 vs 深克隆
  • 浅克隆
@Getter
@AllArgsConstructor
public class Sub {
    private String sName;
}

@AllArgsConstructor
public class Parent implements Cloneable {
    private String pName;
    private Sub sub;

    @Override
    protected Object clone() {
        Parent parent = null;

        try {
            parent = (Parent) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return parent;
    }

    public static void main(String[] args) {
        Sub sub = new Sub("sName");
        Parent parent = new Parent("pName", sub);
        Parent clone = (Parent) parent.clone();

        System.out.println("==============parent===================");
        System.out.println(parent.hashCode());
        System.out.println(parent.pName);
        System.out.println(parent.sub.hashCode());
        System.out.println(parent.sub.getSName());

        System.out.println("================clone===================");
        System.out.println(clone.hashCode());
        System.out.println(clone.pName);
        System.out.println(clone.sub.hashCode());
        System.out.println(clone.sub.getSName());

        System.out.println("=================hashcode================");
        System.out.println(parent.hashCode() == clone.hashCode());
        System.out.println(parent.sub.hashCode() == clone.sub.hashCode());
    }
}

输出:
==============parent===================
166239592
pName
991505714
sName
================clone===================
385242642
pName
991505714
sName
=================hashcode================
false
true
  • 深克隆
@Getter
@AllArgsConstructor
public class Sub implements Cloneable {
    private String sName;

    @Override
    protected Sub clone() {
        Sub sub = null;
        try {
            sub = (Sub) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sub;
    }
}

@AllArgsConstructor
public class Parent implements Cloneable {
    private String pName;
    private Sub sub;

    @Override
    protected Object clone() {
        Parent parent = null;

        try {
            parent = (Parent) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        assert parent != null;
        parent.sub = sub.clone();
        return parent;
    }

    public static void main(String[] args) {
        Sub sub = new Sub("sName");
        Parent parent = new Parent("pName", sub);
        Parent clone = (Parent) parent.clone();

        System.out.println("==============parent===================");
        System.out.println(parent.hashCode());
        System.out.println(parent.pName);
        System.out.println(parent.sub.hashCode());
        System.out.println(parent.sub.getSName());

        System.out.println("================clone===================");
        System.out.println(clone.hashCode());
        System.out.println(clone.pName);
        System.out.println(clone.sub.hashCode());
        System.out.println(clone.sub.getSName());

        System.out.println("=================hashcode================");
        System.out.println(parent.hashCode() == clone.hashCode());
        System.out.println(parent.sub.hashCode() == clone.sub.hashCode());
    }
}


输出:
==============parent===================
166239592
pName
991505714
sName
================clone===================
385242642
pName
824009085
sName
=================hashcode================
false
false
实现Serializable接口,深克隆
public class CloneUtils {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj){
        T cloneObj = null;
        try {
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(obj);
            obs.close();

            //分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);

            //返回生成的新对象
            cloneObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }
}

@Getter
@AllArgsConstructor
public class Sub implements Serializable {
    private String sName;
}

@AllArgsConstructor
public class Parent implements Serializable {
    private String pName;
    private Sub sub;

    public static void main(String[] args) {
        Sub sub = new Sub("sName");
        Parent parent = new Parent("pName", sub);
        Parent clone = CloneUtils.clone(parent);

        System.out.println("==============parent===================");
        System.out.println(parent.hashCode());
        System.out.println(parent.pName);
        System.out.println(parent.sub.hashCode());
        System.out.println(parent.sub.getSName());

        System.out.println("================clone===================");
        System.out.println(clone.hashCode());
        System.out.println(clone.pName);
        System.out.println(clone.sub.hashCode());
        System.out.println(clone.sub.getSName());

        System.out.println("=================hashcode================");
        System.out.println(parent.hashCode() == clone.hashCode());
        System.out.println(parent.sub.hashCode() == clone.sub.hashCode());
    }
}

输出:

==============parent===================
708049632
pName
716083600
sName
================clone===================
1791930789
pName
762152757
sName
=================hashcode================
false
false

扩展

  • 标识接口 : Java语言提供的Cloneable接口和Serializable接口的代码非常简单,它们都是空接口,这种空接口也称为标识接口,标识接口中没有任何方法的定义,其作用是告诉JRE这些接口的实现类是否具有某个功能,如是否支持克隆、是否支持序列化等。

参考

相关文章

  • java 对象的拷贝

    拷贝:即复制 对象拷贝:即对象复制 java 对象拷贝分类:浅拷贝、深拷贝 java 对象的浅拷贝和深拷贝针对包含...

  • Java基础 - 深拷贝和浅拷贝

    Java 的深拷贝和浅拷贝 什么是深拷贝、浅拷贝 (深克隆、浅克隆)? 在 Java 中,数据类型分为 基本数据类...

  • java中的深拷贝和浅拷贝

    简单记录一下java中的深拷贝和浅拷贝,深拷贝和浅拷贝只是针对对象而言的. 1 深拷贝代码 2 浅拷贝代码 3 测...

  • js浅拷贝深拷贝

    js浅拷贝,深拷贝的简单实现 基础数据 浅拷贝 深拷贝

  • Java基础系列-浅拷贝和深拷贝

    原创文章,转载请标注出处:《Java基础系列-浅拷贝和深拷贝》 一、概述 Java中的拷贝功能是由Object类的...

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • 深拷贝和浅拷贝(Shallow Copy and Deep Co

    概述 这里的拷贝是指在java中如何将对象复制一份。有深拷贝和浅拷贝之分。 浅拷贝是对象在复制时,基础数据类型进行...

  • Java------List的深拷贝与浅拷贝

    Java的浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。 浅拷贝(Shallow Copy) ...

  • Java的浅拷贝和深拷贝

    首先需要明白,浅拷贝和深拷贝都是针对一个已有对象的操作。那先来看看浅拷贝和深拷贝的概念。 在 Java 中,除了基...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

网友评论

      本文标题:Java基础 - 深拷贝和浅拷贝

      本文链接:https://www.haomeiwen.com/subject/ccxajqtx.html