Java中类型为Varargs的类型

时间:2014-10-02 21:59:46

标签: java generics superclass variadic-functions

例如,如果我有一个方法,对于扩展超类的类类型使用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 {}

为什么会这样?

2 个答案:

答案 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通过使用ExampleE满足上限通配符来推断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)