2012-09-22 107 views
5

我有兩個對象使用真正類似的方法,只保存一行。例如:在Java中創建抽象類中的新對象

public class Cat extends Animal 
public class Dog extends Animal 

,他們都使用抽象類Animal一個breed方法。一個叫new Dog(),另一個叫new Cat()。現在我只是在Animal中聲明它爲abstract public void breed();,但是有沒有辦法將它推廣,所以我不必將其作爲一個被覆蓋的抽象方法?

+0

是的,它是沒有必要的,在一個類中的所有方法都需要是抽象 –

+1

@SashiKant雖然如此,我不認爲這是OP是問什麼...... –

回答

3

有很多方法可以做到這一點,假設你的意思是「創造我的孩子」。

反射

首先是使用反射。如果你有你的類無參數的構造,這是因爲調用Class.newInstance一樣容易:

public Animal breed() { 
    try { 
     return (Animal) getClass().newInstance(); 
    } catch (Exception ex) { 
     // TODO Log me 
     return null; 
    } 
} 

如果你沒有在所有的子類的無參數的構造函數,你必須有一個統一的構造函數遍歷所有的子類。舉例來說,如果你有Cat(int, String)Dog(int, String),那麼你就需要通過Class.getConstructor得到構造函數和調用上newInstance

return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed"); 

intString這裏可能是年齡和名字,例如。這就是你如何用反射來做到這一點。

提供商

另一種方法是使用這個簡單的接口:

public interface Provider<T> { 
    T create(); 
} 

然後讓你的抽象類採取了這樣的一個實例在其構造:

public abstract class Animal { 
    private final Provider<Animal> animalProvider; 

    protected Animal(... , Provider<Animal> animalProvider) { 
     // ... 
     this.animalProvider = animalProvider; 
    } 

    public Animal breed() { 
     return animalProvider.create(); 
    } 
} 

然後你子類會將Provider<Animal>傳遞給超類,它將創建子類的新實例:

public class Dog extends Animal { 
    public Dog(...) { 
     super(... , new DogProvider()); 
     // ... 
    } 

    private static class DogProvider implements Provider<Animal> { 
     public Animal create() { 
      return new Dog(...); 
     } 
    } 
} 

對其他子類也做同樣的事情。

注意:如果通過breed您的意思是「得到我的類型」,那麼你應該編輯你的問題說出來。如果這是你的意思,那麼這是一個可行的解決方案:

public abstract class Animal { 
    protected final Breed breed; 

    protected Animal(... , Breed breed) { 
     // ... 
     this.breed = breed; 
    } 

    public Breed getBreed() { 
     return breed; 
    } 
} 

我建議您按照get/set約定數據容器的方法。 Java擁有旨在處理這些命名約定的bean類,它在很多平臺上或多或少都是標準。爲了您的子類:

public class Dog extends Animal { 
    public Dog(...) { 
     super(... , new Breed(...)); 
     // ... 
    } 
} 
2

不,沒有。你必須有一些像你做了什麼,如下

我想你想在你的抽象類有

public abstract Breed getBreed(); 

,然後在每個子類有

public Breed getBreed() { 
    return new DogBreed(); 
} 

和類似的一隻迴歸的貓。

已經在動物類中調用一個品種保護地。這可以在每個子類中初始化。這將消除對抽象方法的需求。例如

public abstract class Animal { 
    Breed breed; 
... 
} 

,然後在狗有

public class Dog extends Animal { 
    public Dog() { 
     breed = new DogBreed(); 
    } 
} 

,並有類似貓的東西。

這可能是值得您同時還通過在品種的狗/貓構造函數,這樣就可以創造出不同品種的狗的對象,而不是限制你的模型狗

的只是一個品種,我不知道在您的示例中,品種必須正確建模。你真的想要新的Dog()成爲一個品種嗎?或者你的意思是打字?在這種情況下,它只是一種動物,而回歸動物的抽象方法就是要走的路。

3

其實,你可以。你需要使用反射這樣的表現可能會有點玄乎,但這種(未經測試)應該工作:

public abstract class Animal{ 
    public Animal breed(){ 
     return getClass().newInstance(); 
    } 
    //other methods 
} 

這將返回實際調用類型的新實例,而不是動物(其中它的實現)的類型。

這實際上有些類似於Prototype Pattern。雖然在這種情況下你正在創建一個新的實例,而不是複製一個現有的實例。

編輯

由於@FrankPavageau在評論中指出,而不是掩蓋在構造異常,您可以通過使用

public abstract class Animal{ 
    public Animal breed(){ 
     return getClass().getConstructor().newInstance(); 
    } 
    //other methods 
} 

這將包裝拋出的任何異常達到同樣的效果在InvocationTargetException這是一個更清潔,可能更容易調試。感謝@FrankPavageau對此建議。

+0

試過,但它拋出了'InstantiationException'。 –

+0

@ Eng.Fouad做了它還是說它需要捕捉它?有很多這方面的例子在網絡上運作。 –

+0

是的,它拋出'InstantiationException'。你可以自己試試:) –