我想创建一个Classes数组,每个类表示我正在构建的系统中可用的类型.涉及的所有类都是公共超类的子类.所以我想做:
Class<? extends SuperClass>[] availableTypes = { SubClass1.class, SubClass2.class };
Run Code Online (Sandbox Code Playgroud)
这给了我错误:
Cannot create a generic array of Class<? extends SuperClass>.
Run Code Online (Sandbox Code Playgroud)
如果我尝试在初始化的右侧限定数组的创建,我会收到相同的消息:
Class<? extends SuperClass>[] availableTypes = Class<? extends SuperClass>[] { SubClass1.class, SubClass2.class };
Run Code Online (Sandbox Code Playgroud)
如果我取消了泛型资格,我可以编译代码:
Class[] availableTypes = { SubClass1.class, SubClass2.class };
Run Code Online (Sandbox Code Playgroud)
但后来我得到了泛型警告:
类是原始类型.应参数化对泛型类的引用.
我尝试着; 我尝试着!:)此外,在这一点上,即使这没有引起警告,我也失去了我试图定义的界面.我不想只返回一个任意类的数组; 我想返回一个类的数组,这些类都是特定SuperClass的子类!
Eclipse有一些非常强大的工具可用于确定用于修复泛型声明的参数,但在这种情况下,它会降低,因为它在处理Class时往往会失败.它提供的"推断通用类型参数"过程根本不会更改代码,而是留下警告.
我可以通过使用Collection来解决这个问题:
List<Class<? extends SuperClass>> availableTypes = new List<Class<? extends SuperClass>>();
Run Code Online (Sandbox Code Playgroud)
但是使用数组做到这一点的正确方法是什么?
eri*_*son 14
使用以下语法:
Class<? extends SuperClass>[] avail = new Class[] { SubClass1.class, ... };
Run Code Online (Sandbox Code Playgroud)
它会给你一个"未经检查"的警告,这是正确的,因为你可能包含一个Class不在SuperClass数组中扩展的类型的对象.
Edd*_*die 12
使用数组执行此操作的正确方法是使用Collection执行此操作.抱歉! 由于一系列复杂的原因,数组与泛型不匹配.数组具有与通用对象不同的协方差模型,这最终会导致您遇到的问题.例如,对于数组,但不是(通常)使用通用对象,您可以合法地执行此操作:
Object[] myArray = new String[5];
Run Code Online (Sandbox Code Playgroud)
虽然你不能这样做:
LinkedList<Object> myCollection = new LinkedList<String>();
Run Code Online (Sandbox Code Playgroud)
如果您想了解更多详细信息,可以从优秀的Generics常见问题解答中看到Arrays In Java Generics页面
正如simonn所说,你也可以按原样使用你的阵列,并@SuppressWarnings("unchecked")用来使警告静音.这将起作用,但没有泛型可以为您提供的类型安全.如果您担心它的性能,只需使用一个,ArrayList所以您只是在数组周围使用一个薄的包装器,但具有泛型提供的所有类型安全保证.
但是使用数组做到这一点的正确方法是什么?
没有类型安全的方法来做到这一点; 使用该集合是正确的方法.要知道为什么,想象一下是否允许这样做.你可能会遇到这样的情况:
// 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>();
Run Code Online (Sandbox Code Playgroud)
类型系统需要检测添加到数组的篮子是类型FruitBasket<? extends Citrus>还是子类型.FruitBasket不匹配,应该拒绝ArrayStoreException.但没有任何反应!
由于类型擦除,JVM只能看到数组的运行时类型.在运行时,我们需要将数组类型与元素类型进行比较,以确保它们匹配.数组的运行时组件类型FruitBasket[]在类型擦除之后; 同样,元素的运行时类型是FruitBasket.没有问题会被发现 - 这就是为什么这是危险的.