您的位置 首页 java

Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

浅拷贝:

  • 定义

比如A被B浅拷贝后,B的所有变量和A的所有变量相同,而且B所有对其他对象的引用任然指向原来的对象,也就是对像浅拷贝只会对主对象(就是A)本身进行拷贝,但不会对主对象里面的对象拷贝,A和B里面的对象引用相同,属于共享状态。

简单说就是,支付至所考虑的对象,而不复制它引用的对象。

  • 浅拷贝前提

首先对象浅拷贝需要实现接口Cloneable

Cloneable接口

Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

空接口

Cloneable是标记型的接口(空接口),它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就CloneNotSupported Exception 异常。可以理解为Cloneable接口发挥的是标记功能,自定义类型需要用户自己标记出哪些类是可以clone的,这个标记就是去实现Cloneable接口,实现了Cloneable接口后就表明该类创建的对象可以被克隆。 而要想使一个类具备拷贝实例的功能,除了要实现Cloneable接口,还必须重写Object类的clone()方法。

  • 代码详解

Group类实现:

super.clone()他会把原对象完整的拷贝过来包括其中的引用,属于欠拷贝

接下里是Group和Person类,用于浅拷贝

 package com.consumer.test;

public class Group implements Cloneable{
    String groupName;

    Person person;

    public String getGroupName() {
        return groupName;
    }

    public  void  setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object object = super.clone();
        return object;
    }
}  
 package com.consumer.test;

public class Person implements Cloneable{
     String  name;

    String sex;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}  

  • 具体实现样例类Shallow copy
 public class ShallowCopy {
    public  static  void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setName("zhangSan");
        person.setSex("17");

        Group group = new Group();
        group.setGroupName("1号组");
        group.setPerson(person);

        Group groupCopy = (Group) group.clone();

        System.out.println("浅拷贝后:");
        System.out.println(groupCopy.getGroupName());
        System.out.println(groupCopy.getPerson().getName());
        System.out.println(groupCopy.getPerson().getSex());

        System.out.println("修改Person信息后:");
        person.setName("liSi");
        person.setSex("28");
        group.setGroupName("copy组");
        System.out.println(groupCopy.getGroupName());
        System.out.println(groupCopy.getPerson().getName());
        System.out.println(groupCopy.getPerson().getSex());
    }
}  

Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

运行结果

从结果发现浅拷贝后复制得到的对象引用的person会随着原对象的改变而变化,但是直接属性String不会随着原对象的修改儿变化。

Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

浅拷贝特点总结:

1.复制得到的对象本身是新对象

2.对象里面的基本数据会复制, 基本数据不存在引用;特殊的String类型,有深拷贝表现;

String 存在于堆内存、常量池;这种比较特殊, 本身没有实现 Cloneable, 传递是引用地址;

由本身的final性, 每次赋值都是一个新的引用地址,原对象的引用和副本的引用互不影响。

因此String就和基本数据类型一样,表现出了”深拷贝”特性.

3.对象里面的复杂数据类型会进行浅拷贝, 指向的同一个引用地址

深拷贝:

DeepGroup

 package com.consumer.test;

public class DeepGroup implements Cloneable{
    String groupName;

    Person person;

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        DeepGroup deepGroup = (DeepGroup)super.clone();

        // 本来是浅复制的,现在讲Person镀锌复制一份重新set进来,因为都是基本类型,都支持深拷贝
        deepGroup.setPerson((Person) deepGroup.getPerson().clone());
        return deepGroup;
    }
}
  

Person

 package com.consumer.test;

public class Person implements Cloneable{
    String name;

    String sex;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
  
  • 具体深拷贝实例:
 package com.consumer.test;

public class DeepGroup implements Cloneable{
    String groupName;

    Person person;

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        DeepGroup deepGroup = (DeepGroup)super.clone();

        // 本来是浅复制的,现在讲Person镀锌复制一份重新set进来,因为都是基本类型,都支持深拷贝
        deepGroup.setPerson((Person) deepGroup.getPerson().clone());
        return deepGroup;
    }
}
  

运行结果:

Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

深拷贝结果

我们发现深拷贝后,复制得到的对象不会受到原来对象的修改而变化的影响了。

Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

深拷贝总结:

所有属性都是一份拷贝, 跟原数据不会有任何耦合(不存在引用共享),我们目前是一层层浅拷贝,实现深拷贝,如果嵌套层次很多会很臃肿,当然我们可以序列化深拷贝: 不需要递归让所有对象实现cloneable接口, 方便简洁。

贴上深拷贝工具类:(此工具类的拷贝类必须都是实现了 Serializable接口 ,支持序列化,否则会报错)

 package com.consumer.test;

import  java .io.*;

public class CloneUtils {
    @SuppressWarnings("unchecked")
    public static <T  extends  Serializable> T deepClone(T obj) {
        T cloneObj = null;
        try {
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(obj);
            obs.close();

            //分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArray InputStream (out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            //返回生成的新对象
            cloneObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }
}
  

序列化 实现深拷贝实现:

 package com.consumer.test;

import com.alibaba.fast JSON .JSONObject;

public class DeepTest {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.setName("zhangSan");
        person.setSex("17");

        DeepGroup deepGroup = new DeepGroup();
        deepGroup.setGroupName("1号组");
        deepGroup.setPerson(person);

        // 序列化——深拷贝
        // 相当于重写字节流, 再创建新对象,  跟原对象没有任何引用共享, 无需嵌套重现 Cloneable.clone(), 只需要实现  Serializable  (每个子类)
        System.out.println("----------------- 序列化-深拷贝测试1 ------------------");
        // 工具类
        DeepGroup deepGroupCopy = CloneUtils.deepClone(deepGroup);

        System.out.println("deepGroup == deepGroupCopy: " + (deepGroup == deepGroupCopy));
        System.out.println("deepGroup.person == deepGroupCopy.person: " + (deepGroup.getPerson() == deepGroupCopy.getPerson()));
        System.out.println("deepGroup.person.name == deepGroupCopy.person.name: " + (deepGroup.getPerson().getName() == deepGroupCopy.getPerson().getName()));

        System.out.println(JSONObject.toJSONString(deepGroup));
        System.out.println(JSONObject.toJSONString(deepGroupCopy));

        System.out.println("----------------- 序列化-深拷贝测试2 ------------------");
        person.setName("liSi");
        person.setSex("132");
        System.out.println(JSONObject.toJSONString(deepGroup));
        System.out.println(JSONObject.toJSONString(deepGroupCopy));

    }
}
  

运行结果:

我们发现序列化可以实现深拷贝,没有问题,到此ok。

  • 你究竟是害怕剑姬还是害怕满是破绽的自己。

如果看到这里,希望大家关注点赞一起交流哈。

文章来源:智云一二三科技

文章标题:Java深拷贝和浅拷贝的区别是什么?序列化实现深拷贝

文章地址:https://www.zhihuclub.com/181778.shtml

关于作者: 智云科技

热门文章

网站地图