在Java中用抽象类创建新对象

ste*_*tes 5 java abstract-class

我有两个使用非常类似方法的对象,除了一行.例如:

public class Cat extends Animal
public class Dog extends Animal
Run Code Online (Sandbox Code Playgroud)

他们都breed在抽象类中使用了一个方法Animal.一个叫new Dog(),另一个叫new Cat().现在我只是abstract public void breed();在动物中声明它,但有没有一种方法可以概括它所以我不必使它成为一个被覆盖的抽象方法?

Bri*_*ian 3

有很多方法可以做到这一点,假设breed你的意思是“创造我的孩子”。

反射

首先是使用反射。如果您的类有一个无参数构造函数,那么这就像调用Class.newInstance一样简单:

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

如果您的所有子类中没有无参数构造函数,则必须在所有子类中具有统一的构造函数。例如,如果您有Cat(int, String)and Dog(int, String),那么您需要通过Class.getConstructor并调用newInstance它来获取构造函数:

return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed");
Run Code Online (Sandbox Code Playgroud)

int例如String,这里可能是年龄和姓名。这就是你如何通过反思来做到这一点。

供应商

另一种方法是使用这个简单的界面:

public interface Provider<T> {
    T create();
}
Run Code Online (Sandbox Code Playgroud)

然后让你的抽象类在它的构造函数中获取它的一个实例:

public abstract class Animal {
    private final Provider<Animal> animalProvider;

    protected Animal( ... , Provider<Animal> animalProvider) {
        // ...
        this.animalProvider = animalProvider;
    }

    public Animal breed() {
        return animalProvider.create();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你的子类会将 a 传递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( ... );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对其他子类也执行相同的操作。

注意:如果breed你的意思是“了解我的类型”,那么你应该编辑你的问题来这么说。如果这就是您的意思,那么这是一个可行的解决方案:

public abstract class Animal {
    protected final Breed breed;

    protected Animal( ... , Breed breed) {
        // ...
        this.breed = breed;
    }

    public Breed getBreed() {
        return breed;
    }
}
Run Code Online (Sandbox Code Playgroud)

我建议遵循数据容器方法的get/set约定。Java 具有旨在处理这些命名约定的 bean 类,并且它或多或少是跨许多平台的标准。对于你的子类:

public class Dog extends Animal {
    public Dog( ... ) {
        super( ... , new Breed( ... ));
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)