浅谈java浅拷贝和深拷贝

前言:深拷贝和浅拷贝的区别是什么? 浅拷贝:被复制的对象的所有变量都含有原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之, 浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。深拷贝:被复制对象的所有变量都含有与原来对象相同的值,而那些引用对象的变量将指向被复制过的新对象,而不再是原有 的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。

浅拷贝

  无论是浅拷贝还是深拷贝都要用到clone()方法,所有类都继承于Object,clone方法定义于Object类中但没有实现,

而如果要使用clone方法,根据源码则必须实现Cloneable接口,java.lang.Cloneable是一个标志性接口不包含任何方法,根据注释clone方法是由C或C++其他本地语言实现的。

  * @return     a clone of this instance.
     * @throws  CloneNotSupportedException  if the object's class does not
     *               support the {@code Cloneable} interface. Subclasses
     *               that override the {@code clone} method can also
     *               throw this exception to indicate that an instance cannot
     *               be cloned.
     * @see java.lang.Cloneable
     */
    protected native Object clone() throws CloneNotSupportedException;

  实现浅拷贝:

package yunche.test.copy;

/**
 * @ClassName: Dog
 * @Description:
 * @author: yunche
 * @date: 2018/08/25
 */
public class Dog implements Cloneable
{
    public String color;
    public int age;

    /**
     * 引用变量
     */
    public Erha erha;

    public static void main(String[] args) throws CloneNotSupportedException
    {
        Dog d = new Dog();
        d.color="yellow";
        d.age=2;
        d.erha = new Erha();
        d.erha.name = "二哈";

        //此时clone方法为浅拷贝
        Dog copyDog = (Dog)d.clone();
        System.out.println(copyDog.color);
        System.out.println(copyDog.age);
        System.out.println(copyDog.erha.name);

        //hashcode不同,创建了新对象
        System.out.println(d==copyDog);
        System.out.println(d.hashCode());
        System.out.println(copyDog.hashCode());

        //hashcode相同,没有创建新的erha对象,只是复制了引用
        System.out.println(copyDog.erha==d.erha);
        System.out.println(copyDog.erha.hashCode());
        System.out.println(d.erha.hashCode());

    }

    private static class Erha
    {
         String name;
    }
}

深拷贝

  深拷贝对于基本数据类型进行值传递,对引用数据类型,创建一个新的对象。并复制其内容。怎么实现深拷贝呢?通常的方案有两种:1.序列化这个对象,再反序列化回来,就可以得到这个新的对象,序列化的规则需要我们自己来写。2.重写clone方法,我们可以对其内部引用类型的变量,再进行一次clone()。

 序列化方式

 序列化需要实现Serializable接口。

package yunche.test.copy;

import java.io.*;

/**
 * @ClassName: Dog
 * @Description:
 * @author: yunche
 * @date: 2018/08/25
 */
public class Dog implements Cloneable, Serializable
{
    public String color;
    public int age;

    /**
     * 引用变量
     */
    public Erha erha;

    public static void main(String[] args) throws CloneNotSupportedException
    {
        Dog d = new Dog();
        d.color="yellow";
        d.age=2;
        d.erha = new Erha();
        d.erha.name = "二哈";

        
        Dog copyDog = (Dog)d.deepClone();
        System.out.println(copyDog.color);
        System.out.println(copyDog.age);
        System.out.println(copyDog.erha.name);

        //hashcode不同,创建了新对象
        System.out.println(d==copyDog);
        System.out.println(d.hashCode());
        System.out.println(copyDog.hashCode());

        //hashcode不同,创建新的erha对象,实现了深拷贝
        System.out.println(copyDog.erha==d.erha);
        System.out.println(copyDog.erha.hashCode());
        System.out.println(d.erha.hashCode());

    }

    public Object deepClone()
    {
        File f = new File("dog.obj");
        Object obj =null;
        try(FileOutputStream fos = new FileOutputStream(f);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            FileInputStream fis = new FileInputStream(f);
            ObjectInputStream ois = new ObjectInputStream(fis))
        {
            oos.writeObject(this);
            obj = ois.readObject();
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        return obj;
    }

    private static class Erha implements Serializable
    {
         String name;
    }
}

 重写clone

package yunche.test.copy;

import java.io.*;

/**
 * @ClassName: Dog
 * @Description:
 * @author: yunche
 * @date: 2018/08/25
 */
public class Dog implements Cloneable
{
    public String color;
    public int age;

    /**
     * 引用变量
     */
    public Erha erha;

    public static void main(String[] args) throws CloneNotSupportedException
    {
        Dog d = new Dog();
        d.color="yellow";
        d.age=2;
        d.erha = new Erha();
        d.erha.name = "二哈";

        //重新clone方法,实现深拷贝
        Dog copyDog = (Dog)d.clone();
        System.out.println(copyDog.color);
        System.out.println(copyDog.age);
        System.out.println(copyDog.erha.name);

        //hashcode不同,创建了新对象
        System.out.println(d==copyDog);
        System.out.println(d.hashCode());
        System.out.println(copyDog.hashCode());

        //hashcode不同,创建新的erha对象,实现了深拷贝
        System.out.println(copyDog.erha==d.erha);
        System.out.println(copyDog.erha.hashCode());
        System.out.println(d.erha.hashCode());

    }

    @Override
    public Object clone()
    {
        try
        {
            Dog dog = (Dog)super.clone();
            dog.erha = (Erha) this.erha.clone();
            return dog;

        }
        catch (CloneNotSupportedException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public static class Erha implements Cloneable
    {
         String name;

         @Override
         public Object clone()
         {
             try
             {
                 return super.clone();
             }
             catch (CloneNotSupportedException e)
             {
                 e.printStackTrace();
             }
             return null;
         }
    }
}

参考资料

  https://segmentfault.com/a/1190000010648514

posted @ 2018-08-25 15:05  云--澈  阅读(583)  评论(0编辑  收藏  举报