[英]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.