首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >引用拷贝、对象拷贝、浅拷贝、深拷贝 到底是什么【详细例子介绍】

引用拷贝、对象拷贝、浅拷贝、深拷贝 到底是什么【详细例子介绍】

作者头像
HaC
发布2021-02-24 11:08:13
3910
发布2021-02-24 11:08:13
举报
文章被收录于专栏:HaC的技术专栏HaC的技术专栏

首先要知道的:

Java的数据类型分为基本数据类型引用数据类型

拷贝一个对象,可以使用 Cloneable接口clone()方法。

对象拷贝分为 浅拷贝深拷贝,这两种拷贝都是从引用拷贝 引出的。

通过下面的例子你就可以明白这三者的区别了。

1、引用拷贝

引用拷贝 简单的说就是通过 = 地址赋值。

class TestClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        String[] hobbies = new String[]{"打篮球", "码代码"};
        Student studentA = new Student(1, "HaC", hobbies);

        System.out.println("------------引用拷贝----------------");
        Student studentB = studentA; //复制引用,这是对象地址赋值
        studentB.setId(2);   //studentA studentB 都是指向同一个地址
        hobbies[0] = "看电影";
        System.out.println("studentA:" + studentA);
        System.out.println("studentC:" + studentB);
        System.out.println("studentA == studentB 的结果:"+(studentA == studentB));
    }
}

@AllArgsConstructor
@Data
public class Student implements Cloneable {
    int id;
    String name;
    String[] hobbies;
}

输出:

------------引用拷贝----------------
studentA:Student(id=2, name=HaC, hobbies=[看电影, 码代码])
studentC:Student(id=2, name=HaC, hobbies=[看电影, 码代码])
studentA == studentB 的结果:true

这里其实是复制了一个地址指向堆,studentAstudentC 两个引用都是指向同一个地址, 这就叫做引用拷贝

2、浅拷贝

Cloneable接口提供了一个clone() 方法进行 对象拷贝 ,我们可以通过实现clone()方法实现浅拷贝或者深拷贝

浅拷贝可以创建一个对象的副本,把基本数据类型和final修饰的数据类型 复制一份,但是如果是引用数据类型,只能复制地址。

class TestClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        String[] hobbies = new String[]{"打篮球", "码代码"};
        Student studentA = new Student(1, "HaC", hobbies);
        
        System.out.println("------------浅拷贝----------------");
        Student studentC = (Student) studentA.clone();
        System.out.println("studentA:" + studentA);
        System.out.println("studentC:" + studentC);
        System.out.println("studentA == studentC 的结果:" + (studentA == studentC));
        studentA.setName("哈希");
        hobbies[0] = "看电影";
        System.out.println("studentA:" + studentA);
        System.out.println("studentC:" + studentC);
    }
}

@AllArgsConstructor
@Data
public class Student implements Cloneable {
    int id;
    String name;
    String[] hobbies;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //浅拷贝
        return super.clone();
    }
}

输出:

------------浅拷贝----------------
studentA:Student(id=1, name=HaC, hobbies=[打篮球, 码代码])
studentC:Student(id=1, name=HaC, hobbies=[打篮球, 码代码])
studentA == studentC 的结果:false
studentA:Student(id=1, name=哈希, hobbies=[看电影, 码代码])
studentC:Student(id=1, name=HaC, hobbies=[看电影, 码代码])

可以看到浅拷贝之后:studentAstudentC是两个不同的地址了,说明clone()方法重新拷贝了一份对象,所以 studentA.setName("哈希"); 仅仅是修改了 studentA 对象。

但是 hobbies[0] = "看电影"; 却是联动的,对 studentAstudentC 两个对象都是有有影响的,说明这个hobbies字段是个地址拷贝

3、深拷贝

浅拷贝是无法把引用对象的值也拷贝的,只是拷贝了地址。

所以如果你要把地址对应的 值也拷贝一份,可以使用深拷贝,实现的原理就是 在clone()方法 再拷贝一份你需要的对象。

class TestClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        String[] hobbies = new String[]{"打篮球", "码代码"};
        Student studentA = new Student(1, "HaC", hobbies);

        System.out.println("------------深拷贝----------------");
        Student studentC = (Student) studentA.clone();
        System.out.println("studentA:" + studentA);
        System.out.println("studentC:" + studentC);
        System.out.println("studentA == studentC 的结果:" + (studentA == studentC));
        studentA.setName("哈希");
        hobbies[0] = "看电影";
        System.out.println("studentA:" + studentA);
        System.out.println("studentC:" + studentC);


    }
}

@AllArgsConstructor
@Data
public class Student implements Cloneable {
    int id;
    String name;
    String[] hobbies;

    @Override
    protected Object clone() throws CloneNotSupportedException {
//         深拷贝,现在将String[]复制一份并重新set进来
        Student student = (Student) super.clone();
        student.setHobbies(student.getHobbies().clone());
        return student;
    }
}

输出:

------------深拷贝----------------
studentA:Student(id=1, name=HaC, hobbies=[打篮球, 码代码])
studentC:Student(id=1, name=HaC, hobbies=[打篮球, 码代码])
studentA == studentC 的结果:false
studentA:Student(id=1, name=哈希, hobbies=[看电影, 码代码])
studentC:Student(id=1, name=HaC, hobbies=[打篮球, 码代码])

深拷贝会 毫无保留地把所有对象都拷贝一份出来,然后修改就是自己的对象。

总结:

1、深拷贝和浅拷贝都是对象拷贝,引用拷贝只是赋值了一个地址,并不是真正的对象的值。

2、浅拷贝

浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址

(1) 对于基本数据类型、final修饰 的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个。

(2) 对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响,联动。

3、深拷贝

深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。

深拷贝把要复制的对象所引用的对象都复制了一遍

区别:

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-02-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、引用拷贝
  • 2、浅拷贝
  • 3、深拷贝
  • 总结:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档