挪用Object.clone()时,实际产生的是什么工作呢?当我们在本身的类里包围clone()时,什么对象对付super.clone()来说是最要害的呢?根类中的clone()要领认真成立正确的存储容量,并通过“按位复制”将二进制位从原始工具中复制到新工具的存储空间。也就是说,它并不可是预留存储空间以及复制一个工具——实际需要观测出欲复制之工具的精确巨细,然后复制谁人工具。由于所有这些事情都是在由根类界说之clone()要领的内部代码中举办的(根类并不知道要从本身这里担任出去什么),所以各人或者已经猜到,这个进程需要用RTTI判定欲克隆的工具的实际巨细。采纳这种方法,clone()要领便可成立起正确数量的存储空间,并对谁人范例举办正确的按位复制。
不管我们要做什么,克隆进程的第一个部门凡是都应该是挪用super.clone()。通过举办一次精确的复制,这样做可为后续的克隆历程成立起一个精采的基本。随后,可采纳另一些须要的操纵,以完成最终的克隆。
为确切相识其他操纵是什么,首先要正确领略Object.clone()为我们带来了什么。出格地,它会自动克隆所有句柄指向的方针吗?下面这个例子可完成这种形式的检测:
//: Snake.java // Tests cloning to see if destination of // handles are also cloned. public class Snake implements Cloneable { private Snake next; private char c; // Value of i == number of segments Snake(int i, char x) { c = x; if(--i > 0) next = new Snake(i, (char)(x + 1)); } void increment() { c++; if(next != null) next.increment(); } public String toString() { String s = ":" + c; if(next != null) s += next.toString(); return s; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) {} return o; } public static void main(String[] args) { Snake s = new Snake(5, 'a'); System.out.println("s = " + s); Snake s2 = (Snake)s.clone(); System.out.println("s2 = " + s2); s.increment(); System.out.println( "after s.increment, s2 = " + s2); } } ///:~
一条Snake(蛇)由数段组成,每一段的范例都是Snake。所以,这是一个一段段链接起来的列表。所有段都是以轮回方法建设的,每做好一段,城市使第一个构建器参数的值递减,直至最终为零。而为给每段赋予一个唯一无二的标志,第二个参数(一个Char)的值在每次轮回构建器挪用时城市递增。
increment()要领的浸染是轮回递增每个标志,使我们能看到产生的变革;而toString则轮回打印出每个标志。输出如下:
s = :a:b:c:d:e s2 = :a:b:c:d:e after s.increment, s2 = :a:c:d:e:f
这意味着只有第一段才是由Object.clone()复制的,所以此时举办的是一种“浅层复制”。若但愿复制整条蛇——即举办“深层复制”——必需在被包围的clone()里采纳附加的操纵。
凡是可在从一个能克隆的类里挪用super.clone(),以确保所有基本类动作(包罗Object.clone())可以或许举办。跟着是为工具内每个句柄都明晰挪用一个clone();不然那些句柄会别名酿成原始工具的句柄。构建器的挪用也大抵沟通——首先结构基本类,然后是下一个衍生的构建器……以此类推,直到位于最深层的衍生构建器。区别在于clone()并不是个构建器,所以没有步伐实现自动克隆。为了克隆,必需由本身明晰举办。