栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 浅拷贝和深拷贝

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 浅拷贝和深拷贝

Java 浅拷贝和深拷贝
  • 浅拷贝和深拷贝
    • 浅拷贝
      • 直接赋值
      • 重写clone()
        • clone的深拷贝方面
        • clone的浅拷贝方面
        • 为啥又有深又有浅
        • 总结
    • 深拷贝
      • 重写clone()
      • new一个新对象
      • 使用序列化和反序列化进行深拷贝
  • [完整代码地址(点个star吧 ball ball了)](https://gitee.com/sssada/base/tree/master/base/clone)

浅拷贝和深拷贝

浅拷贝:直接复制了对象A地址给另一个对象B。由于对象A,B指向的是同一个地址因此修改B,A也会跟着改变。

深拷贝:复制了对象A的值给另一个对象B,这两个对象没有任何关系指向不同的地址。修改其中一个并不会对另一个造成影响。

浅拷贝

先把要用到的两个类放上来,一个狗类,一个毛类。get()、set()什么的就不放了。

class Dog{
    private String name;
    private int age;
    private String color;
    private Mao mao;
    }
class Mao {
    private String changduan;
    private String color;
    }
直接赋值
public void assign() {
		Dog d1 = new Dog("d1", 1, "green");
        Dog d2 = d1;
        d2.setName("d2");
        // 可以看到修改了d2后,d1也改变了
        System.out.println("d1 name:" + d1.getName());
        System.out.println("d2 name:" + d2.getName());
    }

输出:
     d1 name:d2
     d2 name:d2
     可以看到修改了d2的name后,d1的name也发生了改变

重写clone()

clone()其实可以说是半深半浅。下面细
可以通过重写Object类的clone()方法来进行拷贝。

clone的深拷贝方面

首先要重写clone()方法需要实现Cloneable接口

class Dog implements Cloneable{
    private String name;
    private int age;
    private String color;
    private Mao mao;
     
    @Override
    public Dog clone() {
        try {
            return (Dog)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    }

然后创建一个一岁长毛狗d1,并使用clone()方法将d1拷贝给d3

  public void clone_() {
      Dog d1 = new Dog("d1", 1, "green");
      Mao mao =new Mao("long","black");
      d1.setMao(mao);
      Dog d3 = d1.clone();
      d3.setAge(2);
      System.out.println("d1:的年龄" + d1.getAge());
      System.out.println("d3:的年龄" + d3.getAge());
    }

输出:
     d1:的年龄1
     d3:的年龄2
     我们发现修改了d3的age后并没有影响到d1。这就是深拷贝。

clone的浅拷贝方面

还是之前那两个对象,只不过这次我们修改其中的Mao(毛) 属性。

    public void clone_() {
        Dog d1 = new Dog("d1", 1, "green");
        Mao mao =new Mao("long","black");
        d1.setMao(mao);
        Dog d3 = d1.clone();
        d3.setAge(2);
        mao.setChangduan("short");
        mao.setColor("red");
        System.out.println("d1的Mao属性" + d1.getMao()+"d1:的年龄" + d1.getAge());
        System.out.println("d3的Mao属性" + d3.getMao()+"d3:的年龄" + d3.getAge());
    }

输出:
     d1的Mao属性Mao [changduan=short, color=red]d1:的年龄1
     d3的Mao属性Mao [changduan=short, color=red]d3:的年龄2
     我们发现修改了修改d3的age年龄属性不会对d1造成影响,但是修改d3的Mao属性就会把d1的Mao属性也改变了。这就是clone()的浅拷贝!

为啥又有深又有浅

如下图所示,虽然重写了clone()方法,拷贝出来的对象指向了不同的地址。但是d1和d3的Mao属性并没被拷贝出来。也就是说d1和d3的属性Mao指向的是同一个地址,所以修改Mao的值,就会同时影响到d1和d3。

总结

可以使用clone()直接深拷贝的:

  1. 本数据类型如int、char等
  2. 基本数据类型的包装类Integer等
  3. String

不可以简单的使用clone()直接深拷贝的:
引用类型的数据如我上面自己定义的Mao类,数组等。
但是重写clone()的时候处理下还是可以深拷贝的

深拷贝 重写clone()

没错又是重写clone(),只要我们对对象中的引用类型进行处理,就可以使用clone进行深拷贝。就是让这个引用类型也重写clone(套娃!)
首先让Mao类也重写clone(),并修改Dog类的clone()逻辑,把拷贝后的Mao赋值给拷贝后的Dog

class Mao implements Cloneable{
    private String changduan;
    private String color;
    }
    @Override
    public Mao clone()  {
        try {
            return (Mao)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
class Dog implements Cloneable{
    private String name;
    private int age;
    private String color;
    private Mao mao;
     
 	@Override
    public Dog clone() {
        try {
            Dog res=(Dog)super.clone();
            res.mao=mao.clone();
            return res;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

然后使用clone()进行拷贝

public void deepClone() {
        Mao mao = new Mao("long", "black");
        d1.setMao(mao);
        Dog d3 = d1.clone();
        d3.setName("d3");
        mao.setChangduan("short");
        mao.setColor("red");
        System.out.println("d1:" + d1);
        System.out.println("d3:" + d3);
    }

d1:Dog [age=1, color=green, mao=Mao [changduan=short, color=red], name=d1]
d3:Dog [age=1, color=green, mao=Mao [changduan=long, color=black], name=d3]
但是如果Mao类里面又有一个引用类型的属性,那就又要继续重写clone()无限套娃很麻烦。
完美实现深拷贝

new一个新对象

我们可以通过new一个新的对象,然后把老对象的值复制给新对象来做到深拷贝(对象较复杂的时候很麻烦)

   public void newObj() {
        Dog d2 = new Dog(d1.getName(), d1.getAge(), d1.getColor());
        d2.setAge(88);
        System.out.println("d1:" + d1);
        System.out.println("d2:" + d2);
    }

老简单了,不多说了

使用序列化和反序列化进行深拷贝

序列化可以把java类的所有数据及其数据类型都输出到IO中,然后反序列化就是从IO中读取这些数据重新生成对象。由于是直接读取值然后新生成一个对象,所以就是深拷贝!

    public void serDeepCopy() throws IOException, ClassNotFoundException {
        Mao mao=new Mao("short", "red");
        d1.setMao(mao);
        //先把序列化数据放到内存操作流buf中
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        ObjectOutputStream obs = new ObjectOutputStream(buf);
        obs.writeObject(d1);
        obs.close();
        //从buf流中读取数据 并反序列化
        ByteArrayInputStream ios = new ByteArrayInputStream(buf.toByteArray());
        ObjectInputStream ois=new ObjectInputStream(ios);
        Dog d4=(Dog)ois.readObject();
        mao.setColor("black");
        d4.setName("d4");
        System.out.println("d1:" + d1);
        System.out.println("d4:" + d4);
    }

d1:Dog [age=1, color=green, mao=Mao [changduan=short, color=black], name=d1]
d4:Dog [age=1, color=green, mao=Mao [changduan=short, color=red], name=d4]

完整代码地址(点个star吧 ball ball了)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/821285.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号