我有一个接收Class<? extends EntityBase>并给出GenericRenderer<? extends EntityBase>的地图。在GenericRenderer<? extends EntityBase>中,有一个名为draw的方法,该方法采用一个SpriteBatch和一个extends EntityBase对象(因为GenericRenderer将<? extends EntityBase>作为通用对象)。

我正在使用地图保存所有实体的渲染器,但是当我调用draw方法时,Eclipse显示此错误:


  类型GenericRenderer的方法draw(SpriteBatch,capture#3-of扩展EntityBase)不适用于参数(SpriteBatch,capture#4-of?扩展EntityBase)


这是我用来遍历实体,将其转换为EntityBase,获取其渲染器并通过它们运行的​​代码:

for(Entity entity : gameStage.getEntityEngine().getEntities()) {
    if(entity instanceof EntityBase) {
         EntityBase entityBase = (EntityBase) entity;

         GenericRenderer<? extends EntityBase> renderer =
                 Betley.instance.renderer.getRenderer(entityBase.getClass());

         renderer.draw(batch, entityBase.getClass().cast(entityBase));
    }
}

最佳答案

? extends EntityBase意味着它可能仅限于一个子类型,但是您不知道是什么子类型。这意味着编译器无法确定您要传递的对象实际上是正确的类型。

假设您有一对名为FooBar的类,它们都扩展了EntityBase。如果renderer变量是GenericRenderer<? extends EntityBase>,则表示它引用的对象可以是GenericRenderer<Foo>,也可以是GenericRenderer<Bar>。编译器不知道哪个,它可能因实体而异。

因此,当您调用draw时,已将entityBase引用转换为特定类型,例如FooBar,但是编译器无法确定它是否是正确的类。您可能试图将Foo传递给实际上是Renderer<Bar>的渲染器,反之亦然。这就是为什么您得到错误。 ? extends EntityBase并不意味着“接受EntityBase的任何子类”,它的意思是“可能限于我们不知道的单个子类”。

我怀疑您的基本设计与Java泛型的工作方式真的不兼容:如果您的Map值为GenericRenderer<? extends EntityBase>,则意味着您打算使用一些GenericRenderer<Foo>值,有些是GenericRenderer<Bar> , 等等。但是在编译时没有关于每个渲染器需要哪种实体类型的信息,因此编译器无法检查您是否将正确的实体类型传递给每个渲染器。

您可能需要将地图的值类型更改为GenericRenderer<EntityBase>,并在每个渲染器的draw方法中进行强制转换,以检查(在运行时)是否传递了正确的实体类型。或者,提出一种不涉及在单个集合中混合使用不同类型渲染器的设计。

10-07 12:22