简体   繁体   English

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

[英]Creating new object in abstract class in Java

I have two objects which use really similar methods, save for one line. 我有两个使用非常类似方法的对象,除了一行。 For example: 例如:

public class Cat extends Animal
public class Dog extends Animal

And they both use a breed method in the abstract class Animal . 他们都在抽象类Animal使用了一种breed方法。 One calls new Dog() , and the other new Cat() . 一个叫new Dog() ,另一个叫new Dog() new Cat() Right now I just have it declared as abstract public void breed(); 现在我只是将它声明为abstract public void breed(); in Animal, but is there a way I can generalize it so I don't have to make it an abstract method to be overridden? 在Animal中,但是有没有办法可以概括它,所以我不必将它作为一个被覆盖的抽象方法?

Actually, yes you can. 实际上,是的,你可以。 You need to use reflection so performance could be a little iffy, but this (untested) should work: 你需要使用反射,所以性能可能有点不确定,但这个(未经测试)应该有效:

public abstract class Animal{
    public Animal breed(){
      return getClass().newInstance();
    }
    //other methods
}

This will return a new instance of the actual calling type, not the type of Animal (where it's implemented). 这将返回实际调用类型的新实例,而不是Animal的类型(实现它的位置)。

This is actually somewhat similar to the Prototype Pattern . 这实际上与原型模式有些相似。 Although in this case you're creating a new instance, not copying an existing instance. 虽然在这种情况下,您正在创建新实例,而不是复制现有实例。

Edit 编辑

As @FrankPavageau pointed out in the comments, rather than masking an exception in the constructor, you can achieve the same result by using 正如@FrankPavageau在注释中指出的那样,不是在构造函数中屏蔽异常,而是可以通过使用来实现相同的结果

public abstract class Animal{
    public Animal breed(){
      return getClass().getConstructor().newInstance();
    }
    //other methods
}

Which will wrap any exception thrown in an InvocationTargetException which is a bit cleaner and probably easier to debug. 这将包装InvocationTargetException中抛出的任何异常,它更清晰,可能更容易调试。 Thanks @FrankPavageau for that suggestion. 感谢@FrankPavageau提出的建议。

There are many ways to do this, assuming by breed you mean "create children of me." 有许多方法可以做到这一点,假设你的breed意味着“创造我的孩子”。

Reflection 反射

First is to use reflection. 首先是使用反射。 If you have a no-args constructor for your classes, this is as easy as calling Class.newInstance : 如果你的类有一个no-args构造函数,那就像调用Class.newInstance一样简单:

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

If you don't have a no-args constructor in all your subclasses, you'll have to have a uniform constructor across all your subclasses. 如果你的所有子类中都没有no-args构造函数,那么你必须在所有子类中都有一个统一的构造函数。 For example, if you have Cat(int, String) and Dog(int, String) , then you need to get the constructor via Class.getConstructor and invoke newInstance on that: 例如,如果你有Cat(int, String)Dog(int, String) ,那么你需要通过Class.getConstructor获取构造函数并在其上调用newInstance

return (Animal) getClass().getConstructor(int.class, String.class).newInstance(0, "Unnamed");

int and String here may be age and name, for example. intString可以是年龄和名称。 This is how you do this with reflection. 这就是你用反射做到这一点的方法。

Providers 供应商

Another way is to use this simple interface: 另一种方法是使用这个简单的界面:

public interface Provider<T> {
    T create();
}

Then have your abstract class take an instance of this in its constructor: 然后让您的抽象类在其构造函数中获取此实例:

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

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

    public Animal breed() {
        return animalProvider.create();
    }
}

Then your subclasses will pass a Provider<Animal> to the superclass which will create new instances of the subclass: 然后您的子类将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( ... );
        }
    }
}

Do the same for other subclasses as well. 对其他子类也这样做。

Note: if by breed you mean "get the type of me," then you should edit your question to say so. 注意:如果你的breed意思是“得到我的类型”,那么你应该编辑你的问题来说明。 If this is what you meant, then this is a viable solution: 如果这是你的意思,那么这是一个可行的解决方案:

public abstract class Animal {
    protected final Breed breed;

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

    public Breed getBreed() {
        return breed;
    }
}

I recommend following the get / set conventions for data container methods. 我建议遵循数据容器方法的get / set约定。 Java has bean classes designed to handle these naming conventions, and it's more or less a standard across many platforms. Java具有设计用于处理这些命名约定的bean类,并且它或多或少是许多平台的标准。 For your subclasses: 对于您的子类:

public class Dog extends Animal {
    public Dog( ... ) {
        super( ... , new Breed( ... ));
        // ...
    }
}

No there isn't. 不,没有。 You will have to have something like what you have done as below 您必须拥有如下所示的内容

I think you want to have in your abstract class 我想你想要在你的抽象课中

public abstract Breed getBreed();

and then in each sub class have 然后在每个子类中都有

public Breed getBreed() {
    return new DogBreed();
}

and a similar one returning cat. 和一个类似的回归猫。

or 要么

Have a protected field in the Animal class called breed. 在Animal类中有一个名为breed的受保护字段。 This could then be initialised in each of the subclasses. 然后可以在每个子类中初始化它。 This would remove the need for an abstract method. 这将消除对抽象方法的需要。 For example 例如

public abstract class Animal {
    Breed breed;
...
}

and then in Dog have 然后在狗有

public class Dog extends Animal {
    public Dog() {
        breed = new DogBreed();
    }
}

and have something similar to Cat. 和猫有类似的东西。

It might be worth you while also passing in the breed to the Dog/Cat ctor so that you can create Dog objects of different breeds rather than restricting your model to just one breed of Dog 将品种传递给Dog / Cat ctor可能是值得的,这样您就可以创建不同品种的Dog对象,而不是将您的模型限制为只有一种狗

I am not sure Breed is necessarily modelled correctly in your example. 我不确定Breed是否必须在您的示例中正确建模。 Do you really want new Dog() to be a breed? 你真的想要新的Dog()成为一个品种吗? Or do you mean type? 或者你的意思是类型? In which case it is just an animal and the abstract method returning animal is the way to go. 在这种情况下,它只是一种动物,返回动物的抽象方法是要走的路。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM