OK York!

像外行一样思考

Archive for the ‘clone’ tag

java中对象的克隆

without comments

    java中对象默认为浅拷贝,要深拷贝时需要重载clone方法。在重载时一般要先调用super.clone().这个super.clone()指的是Object类里面定义的clone方法。它根据实际对象的大小来分配空间,并且把内存里面的内容复制过去。如果是基本类型则直接复制,对象类型则只是复制一个引用。

Object类的clone方法是一个native的方法。它先检查当前对象是不是已经实现了Cloneable的接口,如果没有,抛出一个异常;如果已经实现了这个接口,则产生这个对象的类的一个新的实例,并且用这个对象的内容去初始化那个新的实例。源代码里的注释如是说。

     * The method clone for class Object performs a 

     * specific cloning operation. First, if the class of this object does 

     * not implement the interface Cloneable, then a 

     * <tt>CloneNotSupportedException is thrown. Note that all arrays 

     * are considered to implement the interface Cloneable. 

     * Otherwise, this method creates a new instance of the class of this 

     * object and initializes all its fields with exactly the contents of 

     * the corresponding fields of this object, as if by assignment; the

     * contents of the fields are not themselves cloned. Thus, this method 

     * performs a “shallow copy” of this object, not a “deep copy” operation.

 

 

public class Main {

       public static void main(String[] args) {

                 B1 b1 = new B1();

                 b1.a = 11;
                 b1.b = 22;
                 b1.c = 33;
                 b1.d = 44;
                 b1.e = 55;

                 B1 b2 = (B1) b1.clone();

                 System.out.println(b2.a);
                 System.out.println(b2.b);
                 System.out.println(b2.c);
                 System.out.println(b2.d);
                 System.out.println(b2.e);
          }

}

class B1 extends A1 {

                 public int d = 4;
                 public int e = 5;

                 public Object clone() {
                          System.out.println("B1's clone() is called");

                           B1 b1;

                           b1 = (B1) super.clone();

                            return b1;

}
}

class A1 implements Cloneable{
                 public int a = 0;
                 public int b = 1;
                 public int c = 2;

                 protected Object clone(){
                 System.out.println("A1's clone() is called");
                          try {
                                  return super.clone();

                           } catch (CloneNotSupportedException e) {
                                  return null;

                           }
                }
}

上述代码的执行路径为:13 – 29 – 34 – 46 – 49 ->Object.clone() ->…..
输出:

B1’s clone() is called
A1’s clone() is called
11
22
33
44
55

Cloneable是一个Marker Interface,它里面是空的,仅仅用来让Object.clone()检查一个对象是否可以被克隆。
上述例子中,29行和46行的clone()调用都不会有问题,与Cloneable无关。仅到了49行后才有影响。
A1或者B2当中至少有一个实现了Cloneable接口,否则会抛异常。

 

但是必须记住,除Object类以外,clone()仅仅是一个普通的方法而已。他们不会去检查是否实现Cloneable(当然良好的习惯要求我们多谢一句instanceof^^)
如果代码改成这样:

public class clone {

public static void main(String[] args) {

B1 b1 = new B1();

b1.a = 11;
b1.b = 22;
b1.c = 33;
b1.d = 44;
b1.e = 55;

B1 b2 = (B1) b1.clone();

System.out.println(b2.a);
System.out.println(b2.b);
System.out.println(b2.c);
System.out.println(b2.d);
System.out.println(b2.e);
}

}

class B1 extends A1 {

public int d = 4;
public int e = 5;

public Object clone() {
System.out.println("B1's clone() is called");
B1 b1;
b1 = (B1) super.clone();
return b1;
}
}

class A1{
public int a = 0;
public int b = 1;
public int c = 2;

protected Object clone(){
System.out.println("A1's clone() is called");
return new B1();
}
}

输出就会变成:

B1’s clone() is called
A1’s clone() is called
0
1
2
4
5

虽然A1和B1都不是Cloneable的,但不会报错。

Written by YorkYu

五月 20th, 2009 at 4:06 下午

Posted in Java基础

Tagged with ,