2013-06-12 16 views
8

你將如何爲具有接口成員變量的類編寫複製構造函數?是否可以使用Java中的接口成員變量爲類編寫複製構造函數?

例如:

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如果是這樣,似乎重複使用類與房子與狗與房子與貓變得錯綜複雜!

+1

如果你想要一個深層拷貝,你應該在Animal中實現一個拷貝構造函數。 – alfasin

+1

你不能簡單地在Animal中實現一個複製構造函數。在這種情況下,你有一個接口IAnimal。所以你需要知道你需要實例化的具體類。 – Mene

回答

6

你有三種選擇:

  1. IAnimal的方法,深入克隆對象(使用庫,如DOM接口,如Node.cloneNode(boolean)
  2. IAnimal的所有實現中創建一個拷貝構造函數,該構造函數接受具體類型並將其作爲一個需求nt,然後用反射來訪問它
  3. 創建一個複製工廠,將手動複製每個實現
  4. 使用一個第三方庫,通過自己的合約爲您實現深度克隆,例如no-args構造函數,非final字段,Serializable類,等等。像上市here

複製方法

#1的那些,做這樣的事情:

public interface IAnimal { 
    IAnimal cloneDeep(); 
} 

實現,在你的具體類型,則調用該方法複製它:

this.pet = pet.cloneDeep(); 

然後在接口中記錄要求,說s沿線的omething:

這個接口必須返回一個對象不是==這種情況下,必須深刻克隆所以這個對象是操作不會導致返回一個操作的實現反之亦然。

實現將不得不遵循本合同以符合接口,但這不會在編譯時強制執行。

拷貝構造函數

嘗試反思訪問拷貝構造函數,然後指出拷貝構造函數在接口,即接口契約的一部分的所有具體實現需要。然後,每個實現應該是這樣的:

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方法對於每種類型的手動。

0

據我所知,在Java中沒有直接的等價物。

「正確」的方法是使界面自我實現Cloanable

最簡單的方法可能是使用反射。我知道有一個庫處理任意對象的深層拷貝,但我現在不記得這個名字。

相關:Java: recommended solution for deep cloning/copying an instance

+2

'Cloneable'在很多方面都被打破了,在'Effective Java'中Josh Bloch建議不要使用它。如果你沒有那本書,你應該。請參閱:http://www.artima.com/intv/bloch13.html –

2

如果我理解你的問題,因爲你不能在一個界面中指定的構造函數,你需要在你的界面聲明一個深複製方法,在你的類實現它。你不能實例化一個接口。根據您的需求,您也可能想要在House中深度複製任何內容。

public interface IAnimal { 
    ... 
    IAnimal deepCopy(); 
} 


public House(House houseIn){ 
    this.pet = houseIn.pet.deepCopy(); 
} 

這個問題當然是由你來決定,不要做錯事。它有點像你不想在這裏有一個接口,而是一個抽象類。

1

好吧,讓我解釋一下這個代碼中的一個問題。請注意,當你有一個接口時,你定義的行爲不是一個對象(或生物)的抽象或身份,如動物。在這種情況下,您需要一個抽象類而不是一個接口。 開始說。您不能在接口上使用構造函數(請參閱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. 
} 
相關問題