这是我要执行的操作的要点:
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()
Dog
,Cat
和其他所有动物类别中。
编辑:我知道在static
类中使用abstract
是错误的。我的问题是如何解决这个问题,以便人们仅定义一次Dog.makeFive()
就可以调用Cat.makeFive()
或makeFive()
。
答案 0 :(得分:0)
这将满足您的问题要求:
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();
}
答案 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>
包含相同的Dog
或Cat
对象,否则还需要将新创建的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
方法使用反射来找到合适的构造函数,但是我个人不建议这样做,因为它很难维护。