java中的 clone方法

java中,clone方法用于复制对象,是一种创建对象的方式。另一种创建对象的方法就是使用new操作符。

new操作符的大致流程是先根据new后的类型确定需要分配多大的内存空间,然后调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象就创建完毕了,然后返回它的地址。

clone方法的大致流程与new操作符类似,第一步是分配内存,大小与调用clone方法对象的内存相同,然后将使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建。

Person p1 = new Person(1,"p1");
Person p2 = (Person) p.clone();

p1和p2是两个不同的对象。但Person中有两个成员变量,age和name。age是int类型,name是String类型。实现如下:

public class Person implements Cloneable{  

    private int age ;  
    private String name;  

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

    public Person() {}  

    public int getAge() {  
        return age;  
    }  

    public String getName() {  
        return name;  
    }  

    @Override 
    protected Object clone() throws CloneNotSupportedException {  
        return (Person)super.clone();  
    }  
}

age是基本数据类型, 那么对它的拷贝就是直接将一个4字节的整数值拷贝。
name是String类型的, 它只是一个引用, 指向一个真正的String对象,那么对它的拷贝有两种方式:
1. 直接将源对象中的name的引用值拷贝给新对象的name字段;
2. 根据原Person对象中的name指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的Person对象的name字段。
这两种拷贝方式分别叫做浅拷贝和深拷贝。

Object中默认的clone方法,是浅拷贝的。如果要在clone对象的时候进行深拷贝,就要实现Clonable接口。覆盖clone方法中,除了调用父类中的clone方法得到一个新的对象,还要将该类中的引用变量也clone出来。

以代码为例:

class Body implements Cloneable{  
    public Head head; 

    public Body() {}  
    public Body(Head head) {this.head = head;}  

    @Override 
    protected Object clone() throws CloneNotSupportedException {  
        return super.clone();  
    }  

}  

class Head {  
    public Face face;  

    public Head() {}  
    public Head(Face face){this.face = face;}  

}  

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));  

}

以上代码中, 有两个主要的类, 分别为Body和Face, 在Body类中, 组合了一个Face对象。当对Body对象进行clone时, 它组合的Face对象只进行浅拷贝。

如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。

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;  
    }  

}

class Head implements Cloneable{  
    public Face face;  

    public Head() {}  
    public Head(Face face){this.face = face;}  

    @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));  

}

body和body1内的head引用指向了不同的Head对象, 也就是说在clone Body对象的同时, 也拷贝了它所引用的Head对象, 进行了深拷贝。

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值