是否可以在Java中为具有接口成员变量的类编写复制构造函数?

时间:2013-06-12 21:24:49

标签: java interface copy-constructor member-variables

如何为具有接口成员变量的类编写复制构造函数?

例如:

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如果是这样的话,似乎重复上课与狗的房子和猫的房子会变得错综复杂!

4 个答案:

答案 0 :(得分:7)

您有三种选择之一:

  1. IAnimal上有一个方法来深度克隆对象(由诸如Node.cloneNode(boolean)之类的DOM接口等库使用)
  2. IAnimal的所有实现中创建一个复制构造函数,该实现采用具体类型并在接口契约中使其成为需求,然后使用反射来访问它
  3. 创建一个手动复制每个实现的复制工厂
  4. 使用第三方库,通过自己的合同为您实现深度克隆,例如no-args构造函数,非最终字段,Serializable类等,如列出的那些{{3} }
  5. 复制方法

    对于#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