java|java中的 clone方法

java中,clone方法用于复制对象,是一种创建对象的方式。另一种创建对象的方法就是使用new操作符。
new操作符的大致流程是先根据new后的类型确定需要分配多大的内存空间,然后调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象就创建完毕了,然后返回它的地址。
【java|java中的 clone方法】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方法, 那么在它之后的所有引用的对象都是被共享的。

    推荐阅读