考虑下面的代码示例:执法在方法普通类型等式约束参数
@SafeVarargs
public static <U> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy; //copy is implicitly cast to Object[] -> no heap pollution
}
public static <U> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values); //why does this compile???
}
我本来期望编译器拒绝sortedCopy(U...)
线,具有以下的理由是:
的返回类型Comparator.naturalOrder()
是Comparator<T>
,其中T
是此方法的泛型类型参数,必须满足约束T extends Comparable<? super T>
。由于该方法不接受任何参数,并且其在上述代码中的调用没有明确指定类型为T
(如Comparator.<U>naturalOrder()
,由于U
未扩展Comparable
,因此Comparator.<U>naturalOrder()
无法编译),因此必须以其他方式推断出T
。我可以看到推断T
的唯一方法是通过方法签名sortedCopy(Comparator<? super U>, U...)
。编译器知道values
的类型,因此可以推断出U
,并且继而可以推断出边界为T
,即有界通配符? super U
。但是编译器应该认识到,任何? super U
都不能满足由Comparator.naturalOrder()
指定的T
的要求,即T extends Comparable<? super T>
,因为U
本身不延伸Comparable<? super U>
,所以U
的任何超类都不能。
让我感到困惑的是编辑器确实在将签名从sortedCopy(U...)
更改为sortedCopy(U[])
时生成错误。我想这与第二种情况有关,U
作为数组的类型在运行时存在,而在第一种情况下,它不是。但我还是不明白为什么这将使问题的有效方法调用,这是因为:
- 据我了解,一般类型的可变参数参数转换为
Object[]
如果值传递给方法因为可变参数是通用的,因此是不可确定的类型,如果我理解正确,那么在上面的代码中就是这种情况,因为sortedCopy(U...)
的U
是不可确定的。但即使如此,为什么编译器没有意识到Object
没有扩展Comparable<? super Object>
? - 前面的参数讨论运行时类型。但是,我们仍然是预编译的,所以关于运行时类型的猜测甚至不应该在这种情况下相关,因为尽管
U
在运行时可能不再存在,但编译器仍然知道它,并且应该能够检查不管方法参数是一个数组还是一个可变参数,都会实现等式约束。
那么,为什么上述代码示例中的问题仍在编译?
除此之外,如果方法sortedCopy(Comparator<? super U>, U...)
的@SafeVarargs
注释不合适,我也将非常感谢您的反馈。我相信是这样,但我对此没有信心。
如果你改变了第二个方法的名字,很明显第一个不是被'sortedCopy(Comparator.naturalOrder(),values)调用的' – Javier
@Javier:我不确定你要去哪里。如果您更改方法的名称,那么不存在任何含糊之处。我的直觉就是保持意图,并用泛型来纠正问题。 – Makoto
这只是另一种证明“不选择比较器作为第一个参数的重载参数”的方法。 OP提示'(比较器 super U>比较器,U ...值)'适用于实际参数'(Comparator.naturalOrder(),values)',但事实上并非如此。 – Javier