Java中的浅拷贝与深拷贝

本文深入解析了Java中的拷贝机制,包括引用拷贝与对象拷贝的区别,以及深拷贝和浅拷贝的概念与实现方法。通过具体示例,详细说明了如何实现对象及其引用对象的深拷贝。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.引用拷贝与对象拷贝

class Person implements Cloneable{
    private String name;
    private int age;

   。。。省略get和set方法
protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

1.引用拷贝

        Person person=new Person("jerry",23);
        Person p=person;
        System.out.println(person);
        System.out.println(p);
Example.jerry.pratice.Person@4554617c
Example.jerry.pratice.Person@4554617c

person和p地址相同,二者引用同一个对象new Person("jerry",23)。并没有创建出一个新的对象。此种为引用拷贝。

引用拷贝:创建一个指向对象的引用变量的拷贝。

2.对象拷贝

【注】实现对象拷贝的类必须实现Cloneable接口,并覆写clone方法。

Person person=new Person("jerry",23);
        Person p1=(Person) person.clone();
        System.out.println(person);
        System.out.println(p1);
Example.jerry.pratice.Person@4554617c
Example.jerry.pratice.Person@74a14482

peson和p1地址不同,即创建了新的对象,而非把仅仅把地址赋给变量。此种为对象拷贝。

二.深拷贝和浅拷贝

【注】深拷贝和浅拷贝都是对象拷贝 

浅拷贝

Def:按位拷贝,会创建一个新对象。这个新对象有原始对象属性值的一份拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址。即如果其中一个对象改变了这个地址,就会影响到另一个对象。【浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象】

class Info implements Cloneable{
    private Person person;
    private String city;
    private int    id;

    。。。。省略get和set方法
    public Object clone() throws CloneNotSupportedException {
        Object object = super.clone();
        return object;
    }
}

在原来的基础上加上Info类,引用原来的Person类

Person person=new Person("jerry",23);
        Info info=new Info();
        info.setCity("北京");
        info.setId(11111);
        info.setPerson(person);

        Info info1=(Info)info.clone();
        System.out.println("拷贝后,,,");
        System.out.println(info);
        System.out.println(info1);
        System.out.println(info1.getId());
        System.out.println(info1.getCity());
        System.out.println(info1.getPerson().getName()+","+info1.getPerson().getAge());
        System.out.println("修改被复制对象中的对象引用");
        info1.getPerson().setName("Tom");
        info1.getPerson().setAge(18);
        System.out.println(info.getPerson().getName()+","+info.getPerson().getAge());
        System.out.println(info1.getPerson().getName()+","+info1.getPerson().getAge());
拷贝后,,,
Example.jerry.pratice.Info@4554617c
Example.jerry.pratice.Info@74a14482
11111
北京
jerry,23
修改被复制对象中的对象引用
Tom,18
Tom,18

结果分析:info和info1指向两个不同的对象,而两个引用info和info1中的两个person引用指向同一个对象,所以person变化时,两个同时发生了变化。即浅拷贝

clone方法存在一个缺陷,它并不会将对象的所有属性全部拷贝过来,而是有选择的拷贝。基本规则如下:

1.基本类型:拷贝其值。如int float等

2.对象:如果变量是一个实例对象,则拷贝其地址引用。即新对象和原来对象共享该实例变量。

3.String字符串:若变量为String字符串则拷贝其地址引用。但在修改时,它会从字符池中重新生成一个新的字符串,原有对象保持不变。

深拷贝

Def:深拷贝会拷贝所有的属性,并且拷贝属性指向的动态分配的内存。即对象和它所引用的对象(对象中的对象)一起拷贝就是深拷贝。相比于浅拷贝,深拷贝速度较慢且花销较大。【即,深拷贝就是把对象引用的对象都复制一份】

    public Object clone() throws CloneNotSupportedException {
//        Object object = super.clone();
//        return object;
        Info info1=(Info)super.clone();
        info1.setPerson((Person)info1.getPerson().clone());//将对象中的对象复制一份重新set
        //info1.person=(Person)peson.clone; 两种方式均可
        return info1;
}
拷贝后,,,
Example.jerry.pratice.Info@4554617c
Example.jerry.pratice.Info@74a14482
11111
北京
jerry,23
修改被复制对象中的对象引用
jerry,23
Tom,18

改写Info类中的clone方法,将Info中的Person也复制一份。可以看到修改拷贝对象中的Person对象时,原来的主对象中的person对应属性并没有改变。

【注】根据上述实例可以知道:如果要深拷贝一个对象,这个对象必须实现cloneable接口,实现clone方法,并在clone方法内部把对象引用的其他对象也要clone一份,所以被引用的对象也要实现cloneable接口和实现clone方法。

CJ:设想,如果当person中有多了一个引用对象为Hobby类,那么进行深拷贝的时候,如果还按照上述的方法,对于两个Info来说,两个独立的Info对象内的head引用已经指向了两个独立的Peson对象,但是对于这两个Person对象来说,它们指向的是同一个Hobby对象,即并没有完全的独立。要保证完全独立,也需将Person中的Hobby对象也拷贝一份。即,让Hobby类也实现Cloneable接口,实现clone方法,并在Person对象的clone方法中拷贝它所引用的Hobby对象。

class Person implements Cloneable{
    private String name;
    private int age;
    private Hobby hobby;
  protected Object clone() throws CloneNotSupportedException {
        //return super.clone();
    Person person=(Person)super.clone;
    peson.hobby=(Hobby)this.hobby.clone;
    }
}
class Hobby implements Cloneable{
    private String ho1;
    private String ho2;
  protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

依次类推,如果Hobby对象还引用的其他的对象比如,Special,如果在Hobby类中的clone方法不处理Special的复制,Info对象拷贝之后会一级一级的引用,引用到同一个Special对象。所以要实现完全独立,只能让Special也拷贝。

如果在拷贝一个对象时,要想让这个拷贝的对象和源对象完全彼此独立,那么在引用链上的每一级对象都要被显式的拷贝。所以创建彻底的深拷贝是非常麻烦的,尤其是在引用关系非常复杂的情况下, 或者在引用链的某一级上引用了一个第三方的对象, 而这个对象没有实现clone方法, 那么在它之后的所有引用的对象都是被共享的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值