我有一个奇怪的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:中定义
类型变量的擦除是对其最左边边界的擦除。
如果两个方法具有相同的擦除,编译器会给您一个错误。