这是一款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};
最后一个是我可以开始工作的唯一选择。我只是忽略了这个警告,但如果真的有可能,我想用泛型来做。
答案 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)
两个问题:
你真的需要一个阵列吗?数组在泛型方面效果不佳。因此ArrayList<LevelFactory>
可能是更好的解决方案
你真的需要向特定类型(Level1Factory,Level2Factory)投降吗?如果他们有一个在LevelFactory
中定义的公共超级方法(比如说Level getLevel()
),则不需要向下转换它们。只需致电getLevel()
,您就可以从工厂获得正确的Level实例。
另一个注意事项,因为这似乎是一个常见的陷阱:
new Class<? extends LevelFactory>
这不是一个有效的声明(如果它是一个数组也无关紧要)。 <? extends T>
仅对左侧的类型有效。它定义了创建的Object的泛型类型可以是T或从T派生。对于集合,这并不意味着它们可以存储T的对象或从T派生(也可以是T的集合)。
List<LevelFactory> list = new ArrayList<LevelFactory>()
这意味着您可以将LevelFactory,Level1Factory和Level2Factory的对象添加到list
。如果您希望从list
接收对象,则其类型为LevelFactory
。
List<? extends LevelFactory> list = new ArrayList<LevelFactory>()
表示您可以从LevelFactory
收到list
的对象。但是,您无法以类型安全的方式向list
添加任何对象,因为您不知道list
的确切泛型类型。这是因为您还可以将new ArrayList<Level1Factory>()
分配给list
。这意味着您甚至无法将LevelFactory
个对象添加到list
,因为它们未实现Level1Factory
。
一般来说,在大多数情况下,集合上的<? extends Something>
并不是您想要的。
答案 2 :(得分:1)
您不能以new SomeClass<Type>[10]
的方式创建数组,但只能这样new SomeClass[10]
。请考虑改为使用ArrayList<SomeClass<Type>>
。