泛型与 &-运算符和顺序的歧义



我有一个奇怪的Java泛型模糊行为,我无法解释:

课堂上的这3种方法:

public static <E extends ClassA & ClassB> void method(E val) {}
public static <E extends ClassC & ClassB & ClassA> void method(E val) {}
public static <E extends ClassB> void method(E val) {}

编译良好。

但那些不是(模糊违规):

public static <E extends ClassA & ClassB> void method(E val) {}
public static <E extends ClassB & ClassC & ClassA> void method(E val) {}
public static <E extends ClassB> void method(E val) {}

(ClassA、ClassB、ClassC都是完全独立的接口!)

由于类型擦除,编译器需要为编译方法中的参数类型选择一个静态已知的类型。

为此,它使用约束列表中的第一个类型。

在您的第一个示例中,这会为每个方法产生一个唯一的类型,因此它会编译为

public static method(ClassA val);
public static method(ClassC val);
public static method(ClassB val);

这是完全合法的(除了您丢失的退货类型);它使用三种不同的参数类型创建了三个重载。

在第二个例子中,这产生了一个歧义:

public static method(ClassA val);
public static method(ClassB val);
public static method(ClassB val);

这是不合法的,因为最后两种方法具有相同的签名。

规范明确记录了这种行为。

这可以通过尝试从每个重载中选择一个单一的约束类型来合法化,这样就不会有冲突,但这将是复杂的&对于较大的约束列表,速度较慢
说明书可能会说:

如果它用于参数列表中类型的擦除,则选择通用方法中类型变量的擦除,以便该方法的每次重载都会在擦除后产生唯一的签名
如果擦除的组合不会产生唯一的签名,则会出现歧义错误。

我怀疑这个问题在NP中。

它在JLS#4.6:中定义

类型变量的擦除是对其最左边边界的擦除。

如果两个方法具有相同的擦除,编译器会给您一个错误。

最新更新