Effective Java第11条:谨慎地覆盖clone,仔细阅读后,我们可以更进一步得出结论:其他接口不要继承(extends扩展)Cloneable接口,其他类不要实现(implements)该接口。如果真的需要对象深度(内存)拷贝,可以考虑使用序列化和反序列化代替实现。

对于clone方法,它本身是浅拷贝,如果拷贝的类持有其他类变量,必须让这个类变量的定义类实现Copy Constructor

另一个实现对象拷贝的好办法就是提供一个拷贝构造器(copy constructor)或者拷贝工厂(copy factory)。拷贝构造器只是一个构造器,它唯一的参数类型是包含该构造器的类,例如:

public Yum(Yum yum)

拷贝工厂是类似于拷贝构造器的静态工厂:

public static Yum newInstance(Yum yum)

拷贝构造器的做法,及其静态工厂方法的变形,都比Cloneable/clone方法具有更多的优势,它们不依赖于某一种很有风险的、语言之外的对象创建机制;它们不要求遵守尚未制定好文档的规范;它们不会与final域的正常使用发生冲突;它们不会抛出不必要的受检异常(check exception);他们不需要进行类型转换。

虽然你不可能把拷贝构造器或者静态工厂放在接口中,但是由于Cloneable缺少一个公有的clone方法,所以它也没有提供一个接口该有的特性。因此,使用拷贝构造器或者拷贝工厂来代替clone方法时,并没有舍弃接口的功能特性。

更进一步,拷贝构造器或者拷贝工厂可以带一个参数,参数类型是通过该类实现的接口。例如,按照惯例,所有通用集合都提供了一个拷贝构造器,它的参数类型为Collection或者Map

基于接口的拷贝构造器和拷贝工厂(更准确说叫’转换构造器conversion constructor‘)和转换工厂(conversion factory)),允许客户选择拷贝的实现类型,而不是强迫用户去接受原始的实现类型。例如,假设你有一个HashSet,并且希望把它拷贝成一个TreeSetclone的方法无法提供这样的功能,但是用转换构造器很容易实现:new TreeSet(s)