gpt4 book ai didi

java - 在方法参数中强制执行泛型类型相等性约束

转载 作者:搜寻专家 更新时间:2023-11-01 02:37:14 24 4
gpt4 key购买 nike

考虑以下代码示例:

@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 而无法编译), T必须以另一种方式推断。我能看到推断的唯一方法T是通过 sortedCopy(Comparator<? super U>, U...) 的方法签名.编译器知道 values 的类型从而可以推断出 U , 反过来也可以推断出 T 的边界, 即有界通配符 ? super U .但是,编译器应该意识到任何 ? super U永远无法满足 T 的要求由 Comparator.naturalOrder() 指定,即 T extends Comparable<? super T> ,因为 U本身不扩展 Comparable<? super U> , 所以 U 的任何父类(super class)型也不能。

让我感到困惑的是,当我从 sortedCopy(U...) 更改签名时,编译器确实 生成错误至 sortedCopy(U[]) .我想这与以下事实有关,在第二种情况下,U在运行时作为数组的类型存在,而在第一种情况下,它不是。但我仍然不明白为什么这会使有问题的方法调用有效,因为:

  1. 据我了解,泛型类型的可变参数被转换为 Object[]。如果作为 vararg 参数传递给方法的值是通用的,因此是不可具体化的类型,如果我理解正确的话,上面的代码就是这种情况,因为 U来自 sortedCopy(U...)是不可具体化的。但即便如此,为什么编译器没有意识到 Object不扩展 Comparable<? super Object>
  2. 前面的论点是关于运行时类型的。然而,我们仍处于预编译阶段,因此关于运行时类型的推测在这种情况下甚至不应该是相关的,因为,虽然 U可能在运行时不再存在,编译器仍然知道它并且应该能够检查是否满足等式约束,无论方法参数是数组还是可变参数。

那么为什么上面代码示例中的问题行仍然可以编译?

除此之外,对于 @SafeVarargs 的反馈,我也将不胜感激。方法注释 sortedCopy(Comparator<? super U>, U...)是不合适的。我相信是的,但我对此没有信心。

最佳答案

Varargs 可能有点偷偷摸摸。我在我的 IDE 中看到的是关于 sortedCopy(U... values)作为递归 方法,这意味着它不会选择带有 Comparator 的重载参数作为它的第一个参数。

如果将其从可变参数更改为数组参数,并传入 int[] ,您会遇到预期的编译失败。

Error:(12, 16) no suitable method found for sortedCopy(java.util.Comparator<T>,U[])
method Foo.<U>sortedCopy(java.util.Comparator<? super U>,U[]) is not applicable
(inferred type does not conform to upper bound(s)
inferred: U
upper bound(s): java.lang.Comparable<? super U>,U,java.lang.Object)
method Foo.<U>sortedCopy(U[]) is not applicable
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))

Error:(18, 47) no suitable method found for sortedCopy(java.util.Comparator<T>,int[])
method Foo.<U>sortedCopy(java.util.Comparator<? super U>,U[]) is not applicable
(inference variable U has incompatible bounds
equality constraints: int
upper bounds: java.lang.Object)
method Foo.<U>sortedCopy(U[]) is not applicable
(cannot infer type-variable(s) U
(actual and formal argument lists differ in length))

如果你传入一个 Integer[] ,或者如果您仅传入可变参数形式,则只会出现第一个错误。

关于picking the most specific method有规则可供词法分析器使用。具体来说,您会被这条规则所困扰:

A type S is more specific than a type T for any expression if S <: T.

更详细:

The subtypes of a type T are all types U such that T is a supertype of U, and the null type.

据此,我们推断,因为泛型不是良好绑定(bind)的,它正在接受 Comparable作为可变参数的一部分。 这就是为什么我的 IDE 选择它作为递归方法,以及为什么当我运行它时我得到一个 StackOverflowError .

如果您将泛型正确绑定(bind)到 <U extends Comparable<U>>,这个问题实际上就会消失以确保它不会拾取任何你实际上无法分类的东西......

public static <U extends Comparable<U>> Object[] sortedCopy(Comparator<? super U> comparator, U... values) {
U[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy, comparator);
return copy;
}

public static <U extends Comparable<U>> Object[] sortedCopy(U... values) {
return sortedCopy(Comparator.naturalOrder(), values);
}

...警告您可能现在有堆污染,引入固定数量的方法会更简单、更简洁。

关于java - 在方法参数中强制执行泛型类型相等性约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45535418/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com