例如,如果我有一个方法,对于扩展超类的类类型使用varargs 这样:
public static <E extends Example> void test(Class<E>... es){}
然后我尝试用两个不同的Example子类调用该方法,我只能在其中创建一个包含两个类的数组时才这样做。
//this does not work
test(E1.class,E2.class);
//this does work
test(new Class[]{E1.class,E2.class});
public class E1 extends Example {}
public class E2 extends Example {}
为什么会这样?
答案 0 :(得分:6)
这一行没有编译:
test(E1.class,E2.class);
只有一个类型参数E
,Java必须与参数的推断类型完全匹配。它无法推断Example
,因为对象是Class<E1>
和Class<E2>
,而不是Class<Example>
。 Java泛型的不变性可以防止这种情况发生。
您可以通过在test
的泛型类型参数上引入上限通配符来解决此问题:
public static <E extends Example> void test(Class<? extends E>... es)
这允许Java通过使用Example
和E
满足上限通配符来推断E1
E2
。
第二行创建Class
es的原始数组,绕过泛型并生成&#34;未经检查的调用&#34;警告。
new Class[]{E1.class,E2.class}
如果您尝试在此处为Class
提供类型参数,则会出现编译器错误以及任何中间合理类型参数:
// Needs Class<Example> but found Class<E1> and Class<E2>
test(new Class<Example>[]{E1.class,E2.class});
// Needs Class<E1> but found Class<E2>
test(new Class<E1>[]{E1.class,E2.class});
// Needs Class<E2> but found Class<E1>
test(new Class<E2>[]{E1.class,E2.class});
通过在这里使用通配符来满足推理只是揭示了这里的真正问题 - 通用数组创建。
// Generic array creation
test(new Class<? extends Example>[]{E1.class,E2.class});
答案 1 :(得分:3)
您可以定义扩展Example的单个类的泛型E.您不能在通话中引用两个不同的类,因为它不知道E是什么类型。它只需要一种类型。
虽然这不起作用:
test(E1.class, E2.class);
这样做:
test(E1.class, E1.class);
你可以用数组做的原因是因为类型擦除。编译器没有看到数组中的类是不同的。
如果您更改方法以接受任何扩展Example
的类,它将起作用。
public static void test(Class<? extends Example>...classes)