2009-04-14 92 views
45

我想创建一个类的数组,每个类表示在我正在构建的系统中可用的类型。所涉及的所有类都是公共超类的子类。所以我喜欢做的事:如何将泛型与类数组一起使用?

Class<? extends SuperClass>[] availableTypes = { SubClass1.class, SubClass2.class }; 

这给我的错误:

Cannot create a generic array of Class<? extends SuperClass>. 

我得到同样的消息,如果我尝试对合格的右手侧阵列的创建初始化:

Class<? extends SuperClass>[] availableTypes = Class<? extends SuperClass>[] { SubClass1.class, SubClass2.class }; 

我可以得到代码编译,如果我消除仿制药的资格:

Class[] availableTypes = { SubClass1.class, SubClass2.class }; 

但后来我得到了仿制药警告:

类是一种原始类型。泛型类的引用应该被参数化。

我在努力;我尝试着! :)此外,在这一点上,即使这不会引发警告,我也会失去一块我正在尝试定义的界面。我不想只返回一个任意类的数组;我想返回一个类的数组,这些类都是特定SuperClass的所有子类的!

Eclipse有一些功能非常强大的工具,用于确定哪些参数用于修正泛型声明,但在这种情况下会下降,因为它在处理Class时往往会这样做。它提供的“推断泛型类型参数”过程根本不会改变代码,而是留下警告。

我能够用集合,而不是来解决此问题:

List<Class<? extends SuperClass>> availableTypes = new List<Class<? extends SuperClass>>(); 

但是,什么是与数组做到这一点的正确方法?

回答

22

这似乎有点失败,但这样的问题正是大多数人避免混合阵列和泛型的原因。由于泛型的实现方式(type erasure),数组和泛型将永远无法很好地协同工作。

两种解决方法:

  • 棒使用集合(例如ArrayList<Class<? extends SuperClass>>),它的工作原理一样好阵列,并且还允许对其进行扩展。
  • 在创建数组的代码上添加@SuppressWarnings("unchecked")注释以及证明其用法的注释。
2

问题是创建一个泛型类型的数组是非法的。解决它的唯一方法是在创建数组时通过转换为泛型类型,但这不是一个很好的解决方案。 (请注意,有可能使用通用阵列,只是没有创建一个:见this question

你应该几乎总是使用列表而不是阵列无论如何,所以我觉得你想出了最好的解决方案已经。

14

使用此语法:

Class<? extends SuperClass>[] avail = new Class[] { SubClass1.class, ... }; 

它会给你一个“未登记”的警告,这是正确的,因为你可能会包括一个类型不数组中延伸SuperClass一个Class对象。

11

用数组做这件事的正确方法是用一个Collection来做到这一点。抱歉!由于一系列复杂的原因,阵列对泛型没有好处。数组与通用对象有不同的协方差模型,最终导致您遇到的问题。例如,使用数组,而不是(通常)与通用的对象,你可以合法地做到这一点:

Object[] myArray = new String[5]; 

,而你不能做到这一点:

LinkedList<Object> myCollection = new LinkedList<String>(); 

如果您想了解更多的细节,你可以看到Arrays In Java Generics优秀Generics FAQ

正如simonn所说,您也可以直接使用您的阵列,并使用@SuppressWarnings("unchecked")来消除警告。这将起作用,但没有泛型可以为您提供的类型安全。如果您担心的是性能,那么只需使用ArrayList,这样您就可以在阵列周围使用薄型包装,但具有泛型提供的所有类型安全保证。

+1

协方差!你说这个坏话! – 2009-04-14 22:29:33

4

But what's the right way to do this with arrays?

没有类型安全的方法来做到这一点; 使用集合是正确的方法。为了明白为什么,想象一下这是否被允许。你可以有一个情况是这样的:

// Illegal! 
Object[] baskets = new FruitBasket<? extends Citrus>[10]; 

// This is okay. 
baskets[0] = new FruitBasket<Lemon>(); 

// Danger! This should fail, but the type system will let it through. 
baskets[0] = new FruitBasket<Potato>(); 

类型系统需要检测被添加到阵列的篮子是否是类型FruitBasket<? extends Citrus>或亚型。 FruitBasket不匹配,应该被ArrayStoreException拒绝。但没有任何反应!

由于类型擦除,JVM只能看到数组的运行时类型。在运行时,我们需要将数组类型与元素类型进行比较,以确保它们匹配。类型擦除后,阵列的运行时组件类型为FruitBasket[];同样,元素的运行时类型为​​。没有问题会被发现 - 这就是为什么这是危险的。

0

不是类型安全的,并与未选中投警告:

Class<? extends SuperClass>[] availableTypes = 
    (Class<? extends SuperClass>[]) 
    (new Class[]{ SubClass1.class, SubClass2.class }); 
相关问题