Cloneable 接口的目的是作为对象的一个 mixin 接口, 表明这样的对象允许克隆.
遗憾的是,因为Object 对象的clone 方法是受保护的, 一个对象仅仅实现了Cloneable, 但能直接调用clone, 所以导致Cloneable 没有成功达到目的.
如果一个类实现了Cloneable, Object 的 clone 方法就返回该对象的逐域拷贝, 否则就会抛出 CloneNotSupportException 异常.
Clone 方法的通用约定是非常弱的:
创建和返回该对象的一个拷贝,这个拷贝的精确含义取决于该对象的类. 通常情况下满足,但是不强制要求一定要满足:
x.clone() != x, x.clone().getClass() == x.getClass(), x.clone.equals(x)
对于实现了 Cloneable 的类, 我们总是期望它能提供一个功能适当的公有的clone的方法.
实际上, clone 方法就是另一个构造器; 必须确保它不会伤害到原始的对象, 并确保正确地创建被克隆对象中的约束条件.
clone 架构与引用可变对象的final域的正常使用是不兼容的.
简而言之, 所有实现了 Cloneable 接口的类都应该用一个公有的方法覆盖 clone.
此公有的clone 方法首先调用 super.clone, 然后修正任何需要修正的域.一般情况下,这意味着要拷贝任何包含内部"深层结构"的可变对象, 并用指向新对象的引用来代替原来指向这些对象的引用. 如果该类只包含基本类型的域,或者指向不可变对象的引用,那么多半情况下是没有域需要修正的.
另一个实现对象拷贝的好办法就是提供一个拷贝构造器,或拷贝工厂:
- 拷贝构造器: public Yum( Yum yum)
- 拷贝工厂: public static Yum nerInstance(Yum yum)
拷贝构造器和拷贝工厂,都比Cloneable/clone方法具有更多的优势:
- 不依赖于某一种有风险的,语言之外的对象创建机制
- 不要求遵守尚未制定好的文档规范
- 不会与final 域的正常使用发生冲突
- 不会抛出不必要的首检异常
- 不需要进行类型转换
Cloneable 具有很多的限制,所以其他的接口都不应该扩展(extend)这个接口, 为了继承而设计的类也不应该实现(implement)这个接口.