从类转换对象以适合通用

时间:2017-05-20 20:13:01

标签: java generics

我的地图收到Class<? extends EntityBase>并提供GenericRenderer<? extends EntityBase>。在GenericRenderer<? extends EntityBase>内部,有一个名为draw的方法,它采用SpriteBatchextends EntityBase的对象(因为GenericRenderer持有<? extends EntityBase>作为通用)。

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

  

GenericRenderer类型中的方法draw(SpriteBatch,capture#3-of?extends EntityBase)不适用于参数(SpriteBatch,capture#4-of?extends 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));
    }
}

1 个答案:

答案 0 :(得分:0)

? 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>,则表示您计划使用{{1}的值},有些是GenericRenderer<Foo>,等等。但是,在编译时没有关于每个渲染器需要哪种实体类型的信息,因此编译器无法检查您是否将正确类型的实体传递给每个渲染器。

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