使类具有克隆本领
尽量克隆要领是在所有类最根基的Object中界说的,但克隆仍然不会在每个类里自动举办。这好像有些不行思议,因为基本类要领在衍生类里是必定能用的。但Java确实有点儿反其道而行之;假如想在一个类里利用克隆要领,独一的步伐就是专门添加一些代码,以便担保克隆的正常举办。
1. 利用protected时的能力
为制止我们建设的每个类都默认具有克隆本领,clone()要领在基本类Object里获得了“保存”(设为protected)。这样造成的效果就是:对那些简朴地利用一下这个类的客户措施员来说,他们不会默认地拥有这个要领;其次,我们不能操作指向基本类的一个句柄来挪用clone()(尽量那样做在某些环境下出格有用,好比用多形性的方法克隆一系列工具)。在编译期的时候,这实际是通知我们工具不行克隆的一种方法——并且最奇怪的是,Java库中的大大都类都不能克隆。因此,如果我们执行下述代码:
Integer x = new Integer(l);
x = x.clone();
那么在编译期,就有一条讨厌的错误动静弹出,汇报我们不行会见clone()——因为Integer并没有包围它,并且它对protected版原来说是默认的)。
可是,假使我们是在一个从Object衍生出来的类中(所有类都是从Object衍生的),就有权挪用Object.clone(),因为它是“protected”,并且我们在一个担任器中。基本类clone()提供了一个有用的成果——它举办的是对衍生类工具的真正“按位”复制,所以相当于尺度的克隆动作。然而,我们随后需要将本身的克隆操纵设为public,不然无法会见。总之,克隆时要留意的两个要害问题是:险些必定要挪用super.clone(),以及留意将克隆设为public。
有时还想在更深层的衍生类中包围clone(),不然就直接利用我们的clone()(此刻已成为public),而那并不必然是我们所但愿的(然而,由于Object.clone()已建造了实际工具的一个副本,所以也有大概答允这种环境)。protected的能力在这里只能用一次:首次从一个不具备克隆本领的类担任,并且想使一个类酿成“可以或许克隆”。而在从我们的类担任的任何场所,clone()要领都是可以利用的,因为Java不行能在衍生之后反而缩小要领的会见范畴。换言之,一旦工具变得可以克隆,从它衍生的任何对象都是可以或许克隆的,除非利用非凡的机制(后头接头)令其“封锁”克隆本领。
2. 实现Cloneable接口
为使一个工具的克隆本领功成圆满,还需要做另一件工作:实现Cloneable接口。这个接口使人稍觉奇怪,因为它是空的!
interface Cloneable {}
之所以要实现这个空接口,显然不是因为我们筹备上溯造型成一个Cloneable,以及挪用它的某个要领。有些人认为在这里利用接口属于一种“欺骗”行为,因为它利用的特性打的是此外主意,而非本来的意思。Cloneable interface的实现饰演了一个标志的脚色,封装到类的范例中。
两方面的原因促成了Cloneable interface的存在。首先,大概有一个上溯造型句柄指向一个基本范例,并且不知道它是否真的能克隆谁人工具。在这种环境下,可用instanceof要害字(第11章有先容)观测句柄是否确实同一个能克隆的工具毗连:
if(myHandle instanceof Cloneable) // …
第二个原因是思量到我们大概不肯所有工具范例都能克隆。所以Object.clone()会验证一个类是否真的是实现了Cloneable接口。若谜底是否认的,则“掷”出一个CloneNotSupportedException违例。所以在一般环境下,我们必需将“implement Cloneable”作为对克隆本领提供支持的一部门。