1

这是一个 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};

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

4

3 回答 3

5

我建议您阅读“Effective Java”一书的第 25 条“优先使用列表而不是数组”。约书亚·布洛赫写道:

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

UPD:也许有具体的例子会更容易理解。

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

所以让我们假设有可能有 Set<Cat>[] (但它不是)。如果有人将此数组转换为 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 :)

于 2012-07-08T20:33:17.393 回答
3

两个问题:

  1. 你真的需要一个数组吗?数组不适用于泛型。所以一个ArrayList<LevelFactory>可能是更好的解决方案

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

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

new Class<? extends LevelFactory>

这不是一个有效的语句(它是否是一个数组并不重要)。<? extends T>仅对左侧的类型有效。它定义了创建的对象的泛型类型可以是 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>()表示您可以接收LevelFactoryfrom的对象list。但是您不能list以类型安全的方式添加任何对象,因为您不知道list. 那是因为您也可以分配new ArrayList<Level1Factory>()list. 这意味着您甚至不能向其中添加LevelFactory对象,list因为它们没有实现Level1Factory.

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

于 2012-07-08T20:48:10.760 回答
1

您不能以这种方式创建数组,new SomeClass<Type>[10]而只能以这种方式创建new SomeClass[10]。考虑ArrayList<SomeClass<Type>>改用。

于 2012-07-08T20:34:45.180 回答