我阅读了有效的Java书,并且不了解一个解释Clonable接口的段落。有人可以解释一下这段话:
...程序员假设他们扩展一个类并调用它 来自子类的
super.clone
,返回的对象将是一个实例 的子类。超类可以提供此功能的唯一方法 功能是返回通过调用super.clone
获得的对象。 如果clone方法返回由构造函数创建的对象,它将会 有错误的班级。
感谢。
答案 0 :(得分:6)
我应该首先注意clone
本身已被打破,并且Sheep(Sheep cloneMe)
之类的复制构造函数比clone
更为优雅,考虑到{ {1}}合同非常薄弱。你可能已经知道了这一点,因为你正在阅读这本书,但值得一试。
无论如何,要回答这个问题:
Cloneable
将创建一个与调用它的对象相同类型的对象。出于这个原因,强烈建议“级联”到Object.clone()
以获得您计划返回的结果。如果有人决定不遵循这个约定,你最终会得到一个破坏约定的类类型的对象,这将导致许多问题。
为了说明我有一个类似的课程
Object
突然间,如果我做了
class Sheep implements Cloneable {
Sheep(String name)...
public Object clone() {
return new Sheep(this.name); // bad, doesn't cascade up to Object
}
}
class WoolySheep extends Sheep {
public Object clone() {
return super.clone();
}
}
我会收到例外情况,因为我从WoolySheep dolly = new WoolySheep("Dolly");
WoolySheep clone = (WoolySheep)(dolly.clone()); // error
返回的内容是dolly.clone()
,而不是Sheep
。
答案 1 :(得分:2)
我不同意@ corsiKa的回答。从Java5.0开始。 Java支持协变返回类型,因此clone()的正确实现应该是:
class Sheep implements Cloneable {
Sheep(String name)...
public Sheep clone() {
return new Sheep(this.name);
}
}
class WoolySheep extends Sheep {
public WoolySheep clone() {
return super.clone(); // compile time error, Type miss match.
}
}
另外,建议的替代拷贝构造函数不支持多态性。考虑以下示例(哪个复制构造函数不能):
interface Animal implements Cloneable {
String whatAreYou()
}
class Cat implements Animal {
String whatAreYou() {
return "I am a cat";
}
Cat clone() {
return new Cat();
}
}
class Dog implements Animal{
String whatAreYou() {
return "I am a dog";
}
Dog clone() {
return new Dog();
}
}
class Lib {
Animal cloneAnimal(Animal animal) {
return animal.clone();
}
}
答案 2 :(得分:1)
class A {
protected Object clone() {
return new A();
}
}
class B extends A implements Cloneable {
public Object clone() {
return super.clone();
}
}
此处A
的{{1}}实施无效,因为这会引发异常:
clone
相反,B obj = (B)(new B()).clone();
必须调用A.clone()
而不是构造函数。然后super.clone()
将生成运行时类型的新对象,而不是编译时类型。
然后将任何字段克隆到此新对象上。如果您已经有一个初始化所有字段(如复制构造函数),那么使用构造函数很有诱惑力,但这会导致任何子类的行为不正确。
如果类是Object.clone()
,那么它没关系,因为它不能有任何子类。