第13 条: 谨慎地覆盖clone
1.一个类要想实现clone,就要实现Cloneable接口,否则抛出异常
2.Cloneable接口的功能就是为了改变Object类中clone方法以返回对象的clone值,这种接口用法不推荐。
3.不可变类不能提供clone方法。
4.clone是浅拷贝,概念参考我的另一篇文章clone深浅拷贝,往往clone出来的对象里面的成员变量和原始的是一个引用,原始对象的成员变量改变,拷贝后的对象也改变了,如果把他当做一个普通的对象来用,往往会产生错误的后果。要想完全和原对象是两个对象,就要执行深拷贝,但是深拷贝又往往是不彻底的。
5.要想clone出一个单独的对象,所有实现了Cloneable 接口的类都该覆盖clone 方法,并且是公有的方法,它的返回类型为类本身。该方法应该先调用super.clone 方法,然后修正任何需要修正的域。
6.提供拷贝构造器或者拷贝工厂来代替clone
//拷贝构造器,参数为拷贝类自身
public Yum(Yum yum){...}
//拷贝工厂
public static Yum newInstance(Yum yum){...}
优势::它们不依赖于某一种很有风险的、语言之外的对象创建机制;它们不要求遵守尚未制定好文档的规范;它们不会与final 域的正常使用发生冲突;它们不会抛出不必要的受检异常;它们不需要进行类型转换。
甚至,拷贝构造器或者拷贝工厂可以带一个参数,参数类型是该类所实现的接口。例如,按照惯例所有通用集合实现都提供了一个拷贝构造器,其参数类型为Collection 或者
Map 接口。基于接口的拷贝构造器和拷贝工厂(更准确的叫法应该是转换构造器( conversionconstructor )和转换工厂( conversion factory )),允许客户选择拷贝的实现类型,而不是强迫客户接受原始的实现类型。例如,假设你有一个HashSet:s ,并且希望把它拷贝成一个TreeSet 。clone 方法无法提供这样的功能,但是用转换构造器很容易实现: new TreeSet<>() 。
既然所有的问题都与Cloneable 接口有关,新的接口就不应该扩展这个接口,新的可扩展的类也不应该实现这个接口。虽然final 类实现Cloneable 接口没有太大的危害,这个应该被视同性能优化,留到少数必要的情况下才使用。总之,复制功能最好由构造器或者工厂提供。这条规则最绝对的例外是数组,最好利用clone 方法复制数组。