[英]Java: How to create new child class instance from abstract parent class?
這是我要執行的操作的要點:
abstract class Animal {
abstract static Animal fromInput(String input); // <- error
static List<Animal> makeFive() {
List<Animal> animals = new ArrayList<Animal>();
animals.add(Animal.fromInput("Input 1"));
animals.add(Animal.fromInput("Input 2"));
animals.add(Animal.fromInput("Input 3"));
animals.add(Animal.fromInput("Input 4"));
animals.add(Animal.fromInput("Input 5"));
return animals;
}
// ^^^ how to this rewrite this so Dog.makeFive() ^^^ //
// ^^^ makes Dogs and Cat.makeFive() makes Cats? ^^^ //
}
class Dog extends Animal {
@Override static Dog fromInput(String input) {
Dog dog = new Dog();
// do some initial dog stuff with input
return dog;
}
}
class Cat extends Animal {
@Override static Cat fromInput(String input) {
Cat cat = new Cat();
// do some initial cat stuff with input
return cat;
}
}
如何正確寫呢?
我希望能夠調用Dog.makeFive()
給我一個List<Dog>
或Cat.makeFive()
給我一個List<Cat>
而不必在Dog
, Cat
和每一個中重新定義makeFive()
其他動物類。
編輯:我知道在abstract
類中使用static
是錯誤的。 我的問題是如何解決這個問題,以便僅定義一次makeFive()
就能調用Dog.makeFive()
或Cat.makeFive()
。
這將滿足您的問題的要求:
public interface Animal<T> {
List<T> makeFive();
}
然后Dog
和Cat
都會實施Animal
public class Dog implements Animal<DogType> {
public Dog(){
super();
}
@Override
public List<DogType> makeFive(){
// do stuff;
}
}
public class Cat implements Animal<CatType> {
public Cat(){
super();
}
@Override
public List<CatType> makeFive(){
// do stuff;
}
}
另外,如果您使用的是Java 8+,則可以將Animal作為接口,並將makeFive
定義為default
方法
public interface Animal<T> {
List<T> makeFive();
}
public abstract class Animal { abstract List<? extends Animal> makeFive(); } class Dog extends Animal { @Override List<Dog> makeFive() { return null; } } class Cat extends Animal { @Override List<Cat> makeFive() { return null; } }
您可以從函數的簽名中刪除static
關鍵字,並將fromInput
方法定義為abstract
abstract class Animal<T> {
abstract T fromInput(String input);
List<T> makeFive() {
List<T> animals = new ArrayList<>();
animals.add(fromInput("Input 1"));
animals.add(fromInput("Input 2"));
animals.add(fromInput("Input 3"));
animals.add(fromInput("Input 4"));
animals.add(fromInput("Input 5"));
return animals;
}
}
class Dog extends Animal<Dog> {
@Override
Dog fromInput(String input) {
Dog dog = new Dog();
// do some initial dog stuff with input
return dog;
}
}
class Cat extends Animal<Cat> {
@Override
Cat fromInput(String input) {
Cat cat = new Cat();
// do some initial cat stuff with input
return cat;
}
}
然后,您可以使用它來實現調用,如下所示-
public class Solution {
public static void main(String[] args) {
/*
* Dog(s)
*/
List<Dog> dogs = new Dog().makeFive();
for (Dog dog : dogs) {
System.err.println(dog.getClass());
}
/*
* Cat(s)
*/
List<Cat> cats = new Cat().makeFive();
for (Cat cat : cats) {
System.err.println(cat.getClass());
}
}
}
除非在超類中明確聲明了它們的子類,否則超類不能調用其子類的實例。 否則,超級類甚至都不了解它們。 因此,對於列表中所需的Dog或Cat的每個實例,都需要從子類中添加它們。
在您的原始設計中,您曾經調用過makeFive,其中包含一個Dog或Cat實例。 您如何期望Animal的父類能夠實例化具有不同狀態的其他類?
即使您有一個支持該接口的接口,每個子類也必須實現該接口以支持其類型。
但是您已經在每個子類中實現了fromInput,那么為什么不忽略該方法而僅實現(或覆蓋)makeFive()? 似乎您正在實現一種方法,而不必實現另一種方法。
最后,這有一個微妙的問題。 除非您希望List<Animal>
包含相同的Dog
或Cat
對象,否則還需要將新創建的List<Animal>
復制到每個Dog
或Cat
實例。 否則,他們將訪問一個空列表(可能為空)。
我希望能夠調用Dog.makeFive()給我一個列表,或致電Cat.makeFive()給我一個列表,而不必在Dog,Cat和所有其他動物類中重新定義makeFive()。
我感到你很痛苦! 看起來似乎很有可能,但是正如其他答案和評論所說,Java出於任何原因都不允許這樣做。
因此,恕我直言,最好的解決方法是在Animal中使用單個makeFive
方法,並將目標類傳遞給它。
因此,您的來電者將是:
List<Dog> dogList = Animal.makeFive(Dog.class);
實現將是:
public abstract class Animal {
public abstract void initialise(String input);
static <T extends Animal> List<T> makeFive(Class<T> clazz) {
List<T> animals = new ArrayList<T>();
animals.add(makeNew(clazz, "Input 1"));
animals.add(makeNew(clazz, "Input 2"));
animals.add(makeNew(clazz, "Input 3"));
animals.add(makeNew(clazz, "Input 4"));
animals.add(makeNew(clazz, "Input 5"));
return animals;
}
private static <T extends Animal> T makeNew(Class<T> clazz, String input) {
T newAnimal;
try {
newAnimal = clazz.newInstance();
newAnimal.initialise(input);
} catch (InstantiationException | IllegalAccessException e) {
newAnimal = null; // Change This !!! Maybe throw exception, or add "throws" to method declaration
}
return newAnimal;
}
}
最后,讓每種動物類型都進行初始化:
class Dog extends Animal {
@Override
public void initialise(String input) {
// do some initial dog stuff with input
}
}
這種方法確實要求每個子類(狗,貓等)都具有無參數的構造函數,但這是Java生態系統中各種對象的相當普遍的要求。
另外,也可以讓Animal.makeNew
方法使用反射來找到合適的構造函數,但是我個人建議不Animal.makeNew
,因為它很難維護。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.