可变参数
如果我举个例子,有一个使用可变参数的类类型的扩展超类像 这样的方法:可变参数
public static <E extends Example> void test(Class<E>... es){}
然后我尝试调用该方法有两种不同的例子的子类,我只能这样做,如果我用它的两个类的数组。
//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 {}
这是为什么?
此行不会编译:
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的原始数组,绕过泛型并生成“未经检查的调用”警告。
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});
您可以定义扩展Example的单个类的泛型E.你不能在你的呼叫中引用两个不同的类,因为它不知道E是什么类型。它只期望一种类型。
虽然这不起作用:
test(E1.class, E2.class);
这并不:
test(E1.class, E1.class);
你可以用一个数组做到这一点的原因是因为类型擦除。编译器没有看到数组中的类是不同的。
如果你改变你的方法来接受任何延伸Example
的类,它就会工作。
public static void test(Class<? extends Example>...classes)
我想你已经解释得很好。但要等同于OP的示例,您的签名应该是'public static
@ 5gon12eder:你给出的签名和这个回答中的签名完全相同,即他们接受完全相同的参数类。更简单的(在这个答案中给出的)应该总是首选的,因为类型参数是不必要的。 – newacct 2014-10-03 03:32:37
@newacct它们接受相同类型的参数,但如果要引用泛型类型,则需要更详细的语法。由于在OP中,'test'返回'void'并且有一个空体,所以您可能会争辩说我们不希望引用该类型,但通常来说,冗长的语法也更加强大。 – 5gon12eder 2014-10-03 03:42:17
非常感谢。这对我的计划永远不会造成伤害,但我一直在为此挠头。我非常感谢澄清。 – Squirvin 2014-10-03 01:47:53