如何使用类的数组generics?
我想创build一个类的数组,每个代表一个在我正在构build的系统中可用的types。 所有涉及的类都是公共超类的子类。 所以我想这样做:
Class<? extends SuperClass>[] availableTypes = { SubClass1.class, SubClass2.class };
这给了我错误:
Cannot create a generic array of Class<? extends SuperClass>.
如果我尝试在初始化的右侧限定数组的创build,我会得到相同的消息:
Class<? extends SuperClass>[] availableTypes = Class<? extends SuperClass>[] { SubClass1.class, SubClass2.class };
如果我消除了generics限定条件,我可以获得代码进行编译:
Class[] availableTypes = { SubClass1.class, SubClass2.class };
但是,我得到了generics警告:
类是一个原始types。 generics类的引用应该被参数化。
我尝试着; 我尝试着! :)另外,在这一点上,即使这不会引发警告,我也会失去一块我正在试图定义的界面。 我不想只返回一个任意类的数组; 我想返回一个特定的SuperClass的所有子类的类的数组!
Eclipse有一些非常强大的工具来确定用来修正generics声明的参数,但是在这种情况下,它会下降,因为它在处理Class时往往会这样做。 它提供的“推断genericstypes参数”过程根本不会改变代码,而是留下警告。
我能够通过使用一个集合来解决这个问题:
List<Class<? extends SuperClass>> availableTypes = new List<Class<? extends SuperClass>>();
但是用数组来做这件事的正确方法是什么?
这似乎有点失败,但这样的问题正是大多数人避免混合arrays和generics的原因。 由于generics的实现方式( types擦除 ),数组和generics将永远不能很好地协同工作。
两种解决方法:
- 坚持使用一个集合(例如
ArrayList<Class<? extends SuperClass>>
),它可以像数组一样工作,也允许扩展。 - 在创build数组的代码上添加一个
@SuppressWarnings("unchecked")
注释以及评论它的用法。
使用这个语法:
Class<? extends SuperClass>[] avail = new Class[] { SubClass1.class, ... };
它会给你一个“未经检查”的警告,正确的是,因为你可能包括一个Class
对象的types没有扩展SuperClass
中的SuperClass
。
用数组来做这件事的正确方法是用一个Collection来完成。 抱歉! 由于一系列复杂的原因,数组不能很好地处理generics。 数组与通用对象有不同的协方差模型,最终导致您遇到的问题。 例如,对于数组,但不是(通常)使用generics对象,则可以合法地执行此操作:
Object[] myArray = new String[5];
而你不能这样做:
LinkedList<Object> myCollection = new LinkedList<String>();
如果你想了解更多的细节,可以看看Generics常见问题解答中的“ Javagenerics数组”一章
正如simonn所说,你也可以直接使用你的数组,并使用@SuppressWarnings("unchecked")
来使警告@SuppressWarnings("unchecked")
。 这将起作用,但是没有generics可以提供的types安全性。 如果你担心的是性能,那么只需要使用一个ArrayList
这样你只需要在数组中使用一个薄包装器,但是generics提供了所有的types安全保证。
但是用数组来做这件事的正确方法是什么?
没有types安全的方法来做到这一点; 使用集合是正确的方法。 看看为什么,想象一下,如果这是允许的。 你可能有这样的情况:
// 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>();
types系统需要检测添加到数组中的篮子是否为FruitBasket<? extends Citrus>
typesFruitBasket<? extends Citrus>
FruitBasket<? extends Citrus>
或一个亚型。 FruitBasket不匹配,应该被ArrayStoreException拒绝。 但没有任何反应!
由于types擦除,JVM只能看到数组的运行时types。 在运行时,我们需要将数组types与元素types进行比较,以确保它们匹配。 types擦除后,数组的运行时组件types为FruitBasket[]
; 同样,元素的运行时types是FruitBasket
。 没有问题会被发现 – 这就是为什么这是危险的。
问题是创build一个genericstypes的数组是非法的。 解决这个问题的唯一方法是在创build数组时通过转换为genericstypes,但这不是一个很好的解决scheme。 (请注意,可以使用通用数组,而不是创build一个:请参阅此问题 。)
你应该几乎总是使用列表而不是数组,所以我认为你已经提出了最好的解决scheme。
不能安全的input警告
Class<? extends SuperClass>[] availableTypes = (Class<? extends SuperClass>[]) (new Class[]{ SubClass1.class, SubClass2.class });