Java:如何从抽象父类创建新的子类实例?

时间:2019-05-30 21:15:20

标签: java

这是我要执行的操作的要点:

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>而不必重新定义makeFive() DogCat和其他所有动物类别中。

编辑:我知道在static类中使用abstract是错误的。我的问题是如何解决这个问题,以便人们仅定义一次Dog.makeFive()就可以调用Cat.makeFive()makeFive()

5 个答案:

答案 0 :(得分:0)

这将满足您的问题要求:

public interface Animal<T> {

    List<T> makeFive();
}

然后DogCat都将实现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();

}

答案 1 :(得分:0)

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;
    }
}

答案 2 :(得分:0)

您可以从函数的签名中删除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());
        }
    }

}

答案 3 :(得分:0)

除非超类中明确声明了它们,否则超类不得调用其子类的实例。否则,超级类甚至都不了解它们。因此,对于列表中所需的Dog或Cat的每个实例,都需要从子类中添加它们。

在您的原始设计中,您曾经调用过makeFive,其中包含一个Dog或Cat实例。您如何期望Animal的父类能够实例化具有不同状态的不同类?

即使您具有支持此功能的接口,每个子类也必须实现该接口以支持其类型。

但是您已经在每个子类中实现了fromInput,那么为什么不忽略该方法而仅实现(或覆盖)makeFive()?似乎您正在实现一种方法,以免必须实现另一种方法。

最后,这有一个微妙的问题。除非您希望List<Animal>包含相同的DogCat对象,否则还需要将新创建的List<Animal>复制到每个Dog或{{1} }实例。否则,他们将访问一个空列表(可能为空)。

答案 4 :(得分:0)

  

我希望能够调用Dog.makeFive()给我一个列表或   Cat.makeFive()给我一个列表,而不必重新定义   狗,猫和其他所有动物类别中的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方法使用反射来找到合适的构造函数,但是我个人不建议这样做,因为它很难维护。