Java中的clone方法之浅拷贝与深拷贝

拷贝对象还是拷贝引用

从上篇Java中对象的创建方式中可知clone方法被对象调用时,会复制对象,即创建了一个与源对象相同的新对象。

拷贝引用

拷贝引用并没有创建一个新的对象,两个引用的地址值是一样的,表示两个引用都指向了同一个对象。

Person p1 = new Person(1, "key");
Person p2 = p1;

拷贝对象

以下方式是真正的克隆了一个对象,两个引用的地址值是不一样的。通过“p3 == p4 ”可以验证。

Person p3 = new Person(1, "key");
Person p4 = (Person) p3.clone();

深拷贝还是浅拷贝

使用clone方法通过复制创建对象,可分为浅拷贝和深拷贝两种。

浅拷贝

如果通过clone方法拷贝的对象中的某个对象, 与源对象中对应的那个对象是同一个对象, 即只对当前对象进行了clone操作,而没有对该对象中的其他对象或更深层的对象进行clone操作,那么这就是浅拷贝。

浅拷贝的实现

只需要对当前拷贝的对象进行处理,该处理指得是:使该类实现Cloneable接口,并重写clone方法。以下两个Person对象的那么的地址值相同,则表示如果只是用Object中默认的clone方法,是浅拷贝的, 例如:

public class Person implements Cloneable{  
    private int id;  
    private String name;  

    public Person(int id, String name) {  
        this.id= id;  
        this.name = name;  
    }  
    public Person() {}  
    public int getId() {  
        return id;  
    } 
    public String getName() {  
        return name;  
    }  
    @Override 
    protected Object clone() throws CloneNotSupportedException {  
        return (Person)super.clone();  
    }  
    public static void main(String[] args){
        Person p1 = new Person(1, "key");
        Person p2 = (Person) p1.clone();
        System.out.println(p1.getName == p2.getName);
    }
}

深拷贝

与浅拷贝相对,深拷贝是指, 通过clone方法拷贝的对象中的其他所有对象, 与源对象中对应的对象不是同一个对象,即对源对象中的每个对象都进行了clone操作。
为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。
如果只是用Object中默认的clone方法,是浅拷贝的

深拷贝的实现

//如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。
static class Body implements Cloneable{  
    public Head head;  
    public Body() {}  
    public Body(Head head) {this.head = head;}  

    @Override 
    protected Object clone() throws CloneNotSupportedException {  
        Body newBody =  (Body) super.clone();  
        newBody.head = (Head) head.clone();  
        return newBody;  
    }  
}  
static class Head implements Cloneable{  

    public Head() {}  
    @Override 
    protected Object clone() throws CloneNotSupportedException {  
        return super.clone();  
    }  
}   
public static void main(String[] args) throws CloneNotSupportedException {  
    Body body = new Body(new Head());  
    Body body1 = (Body) body.clone();  
    System.out.println("body == body1 : " + (body == body1) );  
    System.out.println("body.head == body1.head : " +  
    (body.head == body1.head));  
}

注意: 如果想要深拷贝一个对象, 这个对象必须要实现Cloneable接口,实现clone方法,并且在clone方法内部,把该对象引用的其他对象也要clone一份,这就要求这个被引用的对象必须也要实现Cloneable接口并且实现clone方法。

如果在Head类中,还引用了其他对象,则必须在Head类的clone方法中将引用的对象也clone一份,才能实现深拷贝。 如果在Head类中没有再引用其他对象,则实现了完全的深拷贝。

完全的深拷贝

由深拷贝的实现,可以得知,若要实现完全的深拷贝,则在引用链上的每一级对象都要被显式的拷贝。如果其中引用了第三方库的对象,则很难实现完全的深拷贝。

图文结合的学习链接(很棒!!!)

学习链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java拷贝拷贝是两种常用的对象拷贝方式。拷贝只会复制对象内部的基本数据类型和引用类型变量的引用,当引用指向的值改变时,拷贝出的新对象也会跟着变化。而拷贝则是与原来的对象完全隔离,互不影响。 要实现拷贝,可以使用clone()方法或重写clone()方法clone()方法是Object类的一个方法,它会创建并返回对象的一个副本,但这个副本仅仅是原始对象的拷贝。我们还可以通过重写clone()方法,实现自定义的拷贝操作。 要实现拷贝,则有两种方法。一种是使用对象序列化,即将对象转换为字节流,然后再转换回对象。这种方法会复制对象内部所有的基本类型和引用类型,从而实现拷贝。另一种方法是手动复制对象的每个属性,将其复制到一个新对象。这种方法需要我们手动处理每个属性的复制过程,确保所有的属性都被复制并且互不影响。 在选择拷贝还是拷贝时,我们需要根据具体情况来决定。如果我们希望拷贝后的新对象与原对象完全隔离,并且对新对象的修改不会影响原对象,那么应该选择拷贝。如果我们希望拷贝后的新对象与原对象共享一些引用类型的属性,并且对新对象的修改会影响原对象,那么可以选择拷贝。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java拷贝拷贝](https://blog.csdn.net/2301_77181435/article/details/130646783)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [java拷贝拷贝](https://blog.csdn.net/weixin_45771158/article/details/125730734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值