我想创建一个Classes数组,每个Classes表示我正在构建的系统中可用的类型。涉及的所有类都是公共超类的子类。所以我想这样做:
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 };
但后来我得到了泛型警告:
Class是原始类型。应该参数化泛型类的引用。
我正在努力;我尝试着! :)此外,在这一点上,即使这没有引起警告,我也失去了我试图定义的界面。我不想只返回一个任意类的数组;我想返回一个类的数组,这些类都是特定SuperClass的子类!Eclipse有一些非常强大的工具可用于确定用于修复泛型声明的参数,但在这种情况下,它会降低,因为它在处理Class时往往会失败。它提供的“推断通用类型参数”程序根本不会更改代码,而是留下警告。
我可以通过使用Collection来解决这个问题:
List<Class<? extends SuperClass>> availableTypes = new List<Class<? extends SuperClass>>();
但是用数组做这个的正确方法是什么?
答案 0 :(得分:23)
这似乎有点失败,但这样的问题正是大多数人避免混合数组和泛型的原因。由于泛型的实现方式(type erasure),数组和泛型将永远无法很好地协同工作。
两个解决方法:
ArrayList<Class<? extends SuperClass>>
),它与数组一样有效,也允许扩展。@SuppressWarnings("unchecked")
注释以及证明其使用的注释。答案 1 :(得分:14)
使用以下语法:
Class<? extends SuperClass>[] avail = new Class[] { SubClass1.class, ... };
它会给你一个“未经检查”的警告,这是正确的,因为你可能包含一个Class
对象,其类型不会在数组中扩展SuperClass
。
答案 2 :(得分:12)
使用数组执行此操作的正确方法是使用Collection执行此操作。抱歉!由于一系列复杂的原因,数组与泛型不匹配。数组具有与通用对象不同的协方差模型,这最终会导致您遇到的问题。例如,对于数组,但不是(通常)使用通用对象,您可以合法地执行此操作:
Object[] myArray = new String[5];
虽然你不能这样做:
LinkedList<Object> myCollection = new LinkedList<String>();
如果您想了解更多详细信息,可以看到优秀Arrays In Java Generics
中的Generics FAQ页面正如simonn所说,您也可以按原样使用数组,并使用@SuppressWarnings("unchecked")
来消除警告。这将起作用,但没有泛型可以为您提供的类型安全。如果您担心它的性能,只需使用ArrayList
,这样您就可以在数组周围使用一个薄的包装器,但具有泛型提供的所有类型安全保证。
答案 3 :(得分:5)
但是用数组做这个的正确方法是什么?
没有类型安全的方法来做到这一点; 使用该集合是正确的方法。要了解原因,想象一下是否允许这样做。你可能会遇到这样的情况:
// 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[]
;同样,元素的运行时类型为FruitBasket
。没有问题会被发现 - 这就是为什么这是危险的。
答案 4 :(得分:2)
问题是创建泛型类型的数组是非法的。解决它的唯一方法是在创建数组时转换为泛型类型,但这不是一个非常好的解决方案。 (请注意,可以使用通用数组,而不是创建一个:请参阅this question。)
你应该几乎总是使用列表而不是数组,所以我认为你已经提出了最好的解决方案。
答案 5 :(得分:0)
不安全且未经检查的投射警告:
Class<? extends SuperClass>[] availableTypes =
(Class<? extends SuperClass>[])
(new Class[]{ SubClass1.class, SubClass2.class });