如何为具有接口成员变量的类编写复制构造函数?
例如:
public class House{
// IAnimal is an interface
IAnimal pet;
public House(IAnimal pet){
this.pet = pet;
}
// my (non-working) attempt at a copy constructor
public House(House houseIn){
// The following line doesn't work because IAnimal (an interface) doesn't
// have a copy constructor
this.pet = new IAnimal(houseIn.pet);
}
}
我是否被迫拥有一个具体的Animal
?如果是这样的话,似乎重复上课与狗的房子和猫的房子会变得错综复杂!
答案 0 :(得分:7)
您有三种选择之一:
IAnimal
上有一个方法来深度克隆对象(由诸如Node.cloneNode(boolean)
之类的DOM接口等库使用)IAnimal
的所有实现中创建一个复制构造函数,该实现采用具体类型并在接口契约中使其成为需求,然后使用反射来访问它Serializable
类等,如列出的那些{{3} } 复制方法
对于#1,请执行以下操作:
public interface IAnimal {
IAnimal cloneDeep();
}
在具体类型中实现它,然后调用该方法来复制它:
this.pet = pet.cloneDeep();
然后在界面中记录需求,说出以下内容:
此接口的实现必须将不是
==
的对象返回到此实例,并且必须进行深度克隆,以便操作此对象不会导致对返回的对象的操作反之亦然。
实现必须遵循此合同才能符合接口,但这不会在编译时强制执行。
复制构造函数
尝试反复访问复制构造函数,然后声明在接口的所有具体实现中都需要复制构造函数,这将成为接口契约的一部分。每个实现都将如下所示:
public class Dog implements IAnimal {
private String name;
public Dog(Dog dog) {
this.name = dog.name;
}
}
然后您只需要一个方法来复制每个实现:
public static <A extends IAnimal> A copy(A animal) {
Class<?> animalType = animal.getClass();
// This next line throws a number of checked exceptions you need to catch
return (A) animalType.getConstructor(animalType).newInstance(animal);
}
你有这个,在你的界面文档中添加一个声明:
此接口的实现必须定义一个复制构造函数,该构造函数接受其类的相同类型或超类型的参数。此构造函数必须对参数进行深层复制,以便操作此对象不会导致操作返回的对象,反之亦然。
同样,这是运行时强制执行的。当构造函数不存在时,上面的copy
方法会抛出NoSuchMethodException
错误。
复制工厂
这需要IAnimal
并使用instanceof
来决定将其传递给哪个方法,例如:
public static IAnimal copyAnimal(IAnimal animal) {
if (animal instanceof Dog)
return copyDog((Dog) animal);
if (animal instanceof Cat)
return copyCat((Cat) animal);
//...
else
throw new IllegalArgumentException("Could not copy animal of type: "
+ animal.getClass().getName());
}
然后手动为每种类型的copy
方法进行深度复制。
答案 1 :(得分:2)
如果我理解你的问题,由于你不能在接口中指定构造函数,你需要在接口中声明一个深层复制方法并在你的类中实现它。您无法实例化接口。您可能还希望根据您的需要对House
中的任何内容进行深层复制。
public interface IAnimal {
...
IAnimal deepCopy();
}
public House(House houseIn){
this.pet = houseIn.pet.deepCopy();
}
问题当然是,由你决定不做错事。它有点像你真的不想要这里的界面,而是一个抽象的类。
答案 2 :(得分:1)
好的,让我解释一下这段代码中的问题。请注意,当您拥有一个接口时,您定义的行为不是对象(或生物)的抽象或身份,例如Animal。在这种情况下,您需要一个抽象类而不是接口。 开始说。你不能在一个接口上有一个构造函数(参见Why are we not allowed to specify a constructor in an interface?),因此使用一个会失败的接口。
所以在这种情况下我会建议使用抽象类:
public class House {
AbstractAnimal pet;
public House(AbstractAnimal pet) {
this.pet = pet;
}
public House(House houseIn) {
this.pet = new AbstractAnimal(houseIn.pet) {
//implement the abstract methods that are required for anonymous class
};
}
private abstract class AbstractAnimal {
//Abstract class attributes
public AbstractAnimal(AbstractAnimal Parent) {
//Constructor code, can also call abstract methods if required
}
//declare Abstract methods if required.
}
答案 3 :(得分:0)
据我所知,在Java中没有直接的等价物。
“正确”的方法是使接口自行实现Cloanable。
最简单的方法可能是使用反射。我知道有一个库可以处理任意对象的深层拷贝,但我现在还记不住这个名字。
相关:Java: recommended solution for deep cloning/copying an instance