Java: 为什么用户必须满足扩展约束?

Java: Why must user satisfy extends constraint?

考虑这段代码:

public class Enclosing {
    class A<X extends Y, Y> {}

    <U, V> void foo(A<U,V> a) {}
}

这给了我一个错误:

Type parameter U is not within its bound; should extend V.

但是,除非你可以构造一个A的实例,否则应该是不可能调用这个函数的,那么为什么foo的声明需要确保U在它的范围内呢?我知道您可以通过传入 null 来违反此规定,但我的直觉是稳健性仍然只要求 "U extends V" 约束在构造 A 时是可证明的,而不是在使用 A 时。

那么,为什么 Java 要求 "U extends V" 在这个声明中是可证明的?为什么要这样设计类型系统?

尽管允许 <U, V> void foo(A<U,V> a) 无害,因为如果 U 没有扩展 V,您将永远无法构造 a 的实例(尽管如您所说,您可以有效地传递 null),编译器 not 发现逻辑上不可能时立即标记它也无济于事。

在您显示的情况下,参数类型 a 在逻辑上是不可能的。类型是 A,类型参数为 U 和 V,其中 U 不被限制为 V 的子类型。我们不能说这种类型 A,因为它们只有存在的类型 A 是类型 A,其中第一个类型参数被限制为第二类型参数的子类型。

如果按照您的建议允许声明,那么也应该允许该声明:

void foo(A<String,Integer> a);

因为在您的推理中,"soundness still only requires that the "String extends Integer" 约束在构造 A 时是可证明的,而不是在使用它时。"

这可能是解决此问题的一种方法,但我认为大多数人更喜欢 Java 编译器在发现不可能时拒绝它们。