簡體   English   中英

在Java中用抽象類創建新對象

[英]Creating new object in abstract class in Java

我有兩個使用非常類似方法的對象,除了一行。 例如:

public class Cat extends Animal
public class Dog extends Animal

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

實際上,是的,你可以。 你需要使用反射,所以性能可能有點不確定,但這個(未經測試)應該有效:

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

這將返回實際調用類型的新實例,而不是Animal的類型(實現它的位置)。

這實際上與原型模式有些相似。 雖然在這種情況下,您正在創建新實例,而不是復制現有實例。

編輯

正如@FrankPavageau在注釋中指出的那樣,不是在構造函數中屏蔽異常,而是可以通過使用來實現相同的結果

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

這將包裝InvocationTargetException中拋出的任何異常,它更清晰,可能更容易調試。 感謝@FrankPavageau提出的建議。

有許多方法可以做到這一點,假設你的breed意味着“創造我的孩子”。

反射

首先是使用反射。 如果你的類有一個no-args構造函數,那就像調用Class.newInstance一樣簡單:

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

如果你的所有子類中都沒有no-args構造函數,那么你必須在所有子類中都有一個統一的構造函數。 例如,如果你有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( ... ));
        // ...
    }
}

不,沒有。 您必須擁有如下所示的內容

我想你想要在你的抽象課中

public abstract Breed getBreed();

然后在每個子類中都有

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

和一個類似的回歸貓。

要么

在Animal類中有一個名為breed的受保護字段。 然后可以在每個子類中初始化它。 這將消除對抽象方法的需要。 例如

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

然后在狗有

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

和貓有類似的東西。

將品種傳遞給Dog / Cat ctor可能是值得的,這樣您就可以創建不同品種的Dog對象,而不是將您的模型限制為只有一種狗

我不確定Breed是否必須在您的示例中正確建模。 你真的想要新的Dog()成為一個品種嗎? 或者你的意思是類型? 在這種情況下,它只是一種動物,返回動物的抽象方法是要走的路。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM