类<! - 扩展SomeSuperclass - >显然是不允许的。有什么意义呢?

时间:2012-07-08 20:16:09

标签: java android generics

这是一款Android应用,但可能在Java中也是如此。我有一个类型LevelFactory,我从中导出Level1Factory,Level2Factory等。我想拥有这些类的数组,所以我可以实例化一个给定数组索引的级别。

我可以拥有一个Class []并将它们放入其中,然后在我需要使用它们时将它们转换为LevelFactory,但我想知道正确的做法是什么。

这显然是错误“不兼容的类型”:

new Class<LevelFactory>[] {Level1Factory.class,Level2Factory.class};

但是,我很惊讶地发现这也是“通用阵列创建”错误:

new Class<? extends LevelFactory>[] {Level1Factory.class,Level2Factory.class};

以下工作原理,但在分配给变量时会给出“未选中分配”警告:

new Class[] {Level1Factory.class,Level2Factory.class};

最后一个是我可以开始工作的唯一选择。我只是忽略了这个警告,但如果真的有可能,我想用泛型来做。

3 个答案:

答案 0 :(得分:5)

我建议你阅读“Effective Java”一书中的第25项“首选列表到数组”。 Joshua Bloch写道:

  

为什么创建通用数组是非法的?因为它不是类型安全的。如果是的话   合法的,由编译器在正确的程序中生成的强制转换可能会失败   运行时带有ClassCastException。这将违反通用类型系统提供的基本保证。

UPD:也许通过具体的例子,它会更容易理解。

首先,数组是协变的,这意味着SuperClass []可以转换为SubClass [],反之亦然。这也意味着将AnyConcreteClass []强制转换为Object []。

所以我们假设可以设置Set&lt; Cat&gt; [](但它不是)。如果有人将此数组转换为Object []然后在其中添加一组Dog实例,则Java无法保证我们的数组仅包含Cat实例集。打破类型安全它打破了泛型的本质。这就是为什么它是非法的通用阵列。

Set<Cat>[] cats = new Set<Cat>[]; // illegal
Object[] objects = cats;
objects[1] = new Set<Dog>();
cats[1].add(new Cat()); // Oops! TypeCastException

老实说这个例子也来自Effective Java:)

答案 1 :(得分:3)

两个问题:

  1. 你真的需要一个阵列吗?数组在泛型方面效果不佳。因此ArrayList<LevelFactory>可能是更好的解决方案

  2. 你真的需要向特定类型(Level1Factory,Level2Factory)投降吗?如果他们有一个在LevelFactory中定义的公共超级方法(比如说Level getLevel()),则不需要向下转换它们。只需致电getLevel(),您就可以从工厂获得正确的Level实例。

  3. 另一个注意事项,因为这似乎是一个常见的陷阱:

    new Class<? extends LevelFactory>

    这不是一个有效的声明(如果它是一个数组也无关紧要)。 <? extends T>仅对左侧的类型有效。它定义了创建的Object的泛型类型可以是T或从T派生。对于集合,这并不意味着它们可以存储T的对象或从T派生(也可以是T的集合)。

    1. List<LevelFactory> list = new ArrayList<LevelFactory>()这意味着您可以将LevelFactory,Level1Factory和Level2Factory的对象添加到list。如果您希望从list接收对象,则其类型为LevelFactory

    2. List<? extends LevelFactory> list = new ArrayList<LevelFactory>()表示您可以从LevelFactory收到list的对象。但是,您无法以类型安全的方式向list添加任何对象,因为您不知道list的确切泛型类型。这是因为您还可以将new ArrayList<Level1Factory>()分配给list。这意味着您甚至无法将LevelFactory个对象添加到list,因为它们未实现Level1Factory

    3. 一般来说,在大多数情况下,集合上的<? extends Something>并不是您想要的。

答案 2 :(得分:1)

您不能以new SomeClass<Type>[10]的方式创建数组,但只能这样new SomeClass[10]。请考虑改为使用ArrayList<SomeClass<Type>>