我如何概括这一点?

How do I generalize this?

我有一个 class ExampleProperty 扩展了 superclass Property 和一个单独的 class, GameObject, 我有ArrayList<Property> properties 以及以下方法,其中 Engine.createEngineObject(new ExampleProperty()) 只是将 new ExampleProperty() 添加到列表中,然后 return 将其返回,propertyId 是 [的继承成员=13=],其中 propertiesProperty 的列表:

public ExampleProperty addExampleProperty()
    {
        ExampleProperty temp = (ExampleProperty)Engine.createEngineObject(new ExampleProperty());
        temp.propertyId = properties.size();
        return temp;
    }

我想推广这个方法,这样我就可以传入一个 Class<?> propertyClass 并让它 return 一个与 propertyClass 类型相同的对象(并在第 3 行执行转换?)。恐怕我对泛化还不够熟悉,所以感谢任何帮助:)

编辑:这是发布答案后修改后的代码。我忘了提及一些信息,但我已经完成了,所以这就是我所拥有的。这可能很糟糕,但它是我的,它有效,我为此感到自豪:

public <T extends Property> T addProperty(Class<T> propertyClass) throws IllegalAccessException, InstantiationException {
        Property property = propertyClass.newInstance();
        if(propertyClass.getSuperclass() == Engine.class)
        {
            Engine temp = Engine.createEngineObject(propertyClass.newInstance());
            temp.propertyId = properties.size();
            return (T)temp;
        }
        T temp = propertyClass.newInstance();
        temp.propertyId = properties.size();
        return (T)temp;
    }

这可能会成功:

public <T extends Property> T createEngineObject(Class<T> propertyClass) throws IllegalAccessException, InstantiationException {
    Property property = propertyClass.newInstance();
    // do something...
    return property;
}

不过,传递 Property 实例似乎是个更好的主意:

public <T extends Property> T createEngineObject(T property) {
    // do something...
    return property;
}

这里的中心问题是您对 ExampleProperty 所做的事情没有在类型中捕获。因此,您不能一字不差地一概而论。

让我们用 currently-hardcoded 类型 (ExampleProperty) 列出您 'do' 的内容,以便我们知道要在类型中捕获什么,以便我们可以概括它:

  • 你调用它的no-args构造函数
  • 您将其结果作为第一个参数传递给 Engine.createEngineObject
  • 您将 createEngineObject 调用的结果转换为这种类型。
  • 您引用了该类型的propertyId字段。
  • 你return类型。

在所有这些操作中,到目前为止问题最大的是第一个:构造函数不参与类型系统。您不能在 java 类型中声明 'has a no-args constructor'。完全没有。随便。

问题有两种解决方法:

  1. 将其仅在零编译时间保证的文档中声明,并使用 java.lang.Class 实例作为载体,以便代码知道从何处获取该构造函数。将不会 compile-time 检查您传递给此方法的泛型形式的任何类型实际上是否具有 no-args 构造函数,或者它是 non-abstract。如果您未能满足这些条件,您唯一知道的方式就是在运行时会发生一些异常。
  2. 使用工厂。

正确答案当然是第二个:使用工厂。捕捉 'a thing that can make ExampleProperty instances' 的概念,因为 可以 在 java 的类型系统中传达。我们可以使用这个工厂作为任何适用于整个类型的工具,如果出现的话:

您的通用代码:

public interface PropertyFactory<P extends Property> {
    P make();
}
// NB: You can replace the above with `java.util.function.Supplier` instead, but I'd make your own type.

public abstract class Property {
    int propertyId;
}

public <P extends Property> P addProperty(PropertyFactory<P> factory) {
    P temp = Engine.createEngineObject(factory.make());
    temp.propertyId = properties.size();
    return temp;
}

// in Engine.java
public <P extends Property> P createEngineObject(P property) {
    // do stuff here
    return property;
}

然后使用:

private static final PropertyFactory<ExampleProperty> EXAMPLE_MAKER = ExampleProperty::new;

ExampleProperty ep = addProperty(EXAMPLE_MAKER);