引用拷贝、浅拷贝和深拷贝区别

类型

拷贝一般分为二大类 引用拷贝对象拷贝,我们通常讲的深拷贝浅拷贝都属于对象拷贝

引用拷贝

顾名思义,即是对引用地址的拷贝,说明引用地址一样,指向堆中的对象是同一个对象。
如果对一个对象进行改变,其他对象也会跟着改变。

对象拷贝

对象拷贝指 对某一对象进行拷贝,是创建了一个全新的对象,也就是内存中存在二个不同地址的对象,这二个对象的基本数据类型变量的内容值都是一样的,但所包含的对象变量的地址可能一样可能不一样,浅拷贝与深拷贝的区别就在这里

现在举个例子:

public static class Person implements Cloneable{
        public String name;
        public int age;
        public House house;

        public Person(String name, int age, House house) {
            this.name = name;
            this.age = age;
            this.house = house;
        }
        
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    public static class House {
        public String address;

        public House(String address) {
            this.address = address;
        }
    }
1.浅拷贝

当前对象里包含有对象变量,如果复制的对象中的对象变量和原对象里的对象地址值是相同的,即引用拷贝,则称之为浅拷贝。我们也可以称之为部分拷贝,即拷贝的不彻底。

public static void main(String[] args) {
        Person person1=new Person("A",20, new House("aa"));
        try {
            Person person2= (Person) person1.clone();

            System.out.println("persion1 = " + person1+" house = "+person1.house);
            System.out.println("persion2 = " + person2+" house = "+person2.house);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }

输出结果

persion1 = Person@402a079c house = House@59ec2012
persion2 = Person@4cf777e8 house =House@59ec2012

可以看到我们对Person1进行了clone,person2的内存地址和person1的不一样,说明这是一个新对象,然而在看对象House,内存地址是一样的,说明对于成员变量只进行了内存引用。这个就是浅拷贝。
总结:虽然对象进行了拷贝,但内部变量没有完全进行拷贝。这就是浅拷贝,即拷贝的不彻底

2.深拷贝

当前对象里包含有对象变量,如果复制的对象中的对象变量和原对象里的对象地址值是不同的,即创建了一个新的对象,则称之为深拷贝。我们也可以称之为完全拷贝,内部进行了彻底拷贝。

现在我们对 clone方法做一些修改

public static class Person implements Cloneable {
        public String name;
        public int age;
        public House house;

        public Person(String name, int age, House house) {
            this.name = name;
            this.age = age;
            this.house = house;
        }

        @Override
        public Object clone() throws CloneNotSupportedException {
            Person person = (Person) super.clone();
            //在原有的基础上 clone了成员变量对象
            person.house = (House) person.house.clone();
            return person;
        }
    }

    public static class House implements Cloneable {
        public String address;

        public House(String address) {
            this.address = address;
        }
        //实现clone方法
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

public static void main(String[] args) {
        Person person1=new Person("A",20, new House("aa"));
        try {
            Person person2= (Person) person1.clone();

            System.out.println("persion1 = " + person1+" house = "+person1.house);
            System.out.println("persion2 = " + person2+" house = "+person2.house);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }

现在我们在来clone,看下会有什么结果

persion1 =Person@402a079c house = House@59ec2012
persion2 = Person@4cf777e8 house = House@2f686d1f

可以看到不仅Person对象内存地址不一样,House的内存地址也不一样了,这说明Person1和Person2的内容,成员变量也完全不相同了。

总结:一个对象进行了clone,不仅仅自身clone了一个新的,其内部的成员变量也都clone了一个新的,这就是深拷贝。

所以,如果一个对象中仅包含基本数据类型,则浅拷贝和深拷贝则没区别。如果一个对象中包含了对象变量,则对这些对象变量的拷贝 就成了 浅拷贝和深拷贝的区别。

再通俗一点讲,换皮不换芯,即浅拷贝。换皮又换芯,即深拷贝。

实现深拷贝的方法

1.可以继承Cloneable 接口

 @Override
    protected Object clone() throws CloneNotSupportedException {
        Person newPerson = (Person)super.clone();
        //对成员变量进行clone
        newPerson.house = (House) newPerson.house.clone();
        return newPerson;
    }

2.通过对象序列化实现深拷贝

public class Person implements Serializable, Cloneable{
    public Object deepClone()  {
        try {
            ByteArrayOutputStream bo= new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bo);
            os.writeObject(this);
            ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi=new ObjectInputStream(bi);
            return(oi.readObject());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值