Java中类型为Varargs的类型

Squ*_*vin 5 java generics variadic-functions superclass

例如,如果我有一个方法,使用类型的varargs扩展超类,如下所示:

public static <E extends Example> void test(Class<E>... es){}
Run Code Online (Sandbox Code Playgroud)

然后我尝试使用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 {}
Run Code Online (Sandbox Code Playgroud)

为什么是这样?

rge*_*man 6

这行不编译:

test(E1.class,E2.class);
Run Code Online (Sandbox Code Playgroud)

只有一个类型参数E,Java必须完全匹配参数的推断类型.它不能推断Example,因为对象是Class<E1>Class<E2>,不是Class<Example>.Java泛型的不变性可以防止这种情况发生.

您可以通过在test泛型类型参数上引入上限通配符来解决此问题:

public static <E extends Example> void test(Class<? extends E>... es)
Run Code Online (Sandbox Code Playgroud)

这允许Java推断ExampleE,通过满足上限通配符E1E2.

第二行创建一个原始的Classes 数组,绕过泛型并生成"未经检查的调用"警告.

new Class[]{E1.class,E2.class}
Run Code Online (Sandbox Code Playgroud)

如果你试图在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}); 
Run Code Online (Sandbox Code Playgroud)

通过在这里使用通配符来满足推理只是揭示了这里的真正问题 - 通用数组创建.

// Generic array creation
test(new Class<? extends Example>[]{E1.class,E2.class});
Run Code Online (Sandbox Code Playgroud)