【发布时间】:2015-04-07 13:58:39
【问题描述】:
以下代码在 Java 7 中编译运行正常,但在 Java 1.8.0 u25 中编译失败:
public class GenericTest {
public static class GenericClass<T> {
T value;
public GenericClass(T value) {
this.value = value;
}
}
public static class SecondGenericClass<T> {
T value;
public SecondGenericClass(T value) {
this.value = value;
}
}
public static<T >void verifyThat(SecondGenericClass<T> actual, GenericClass<T> matcher) {
}
public static<T >void verifyThat(T actual, GenericClass<T> matcher) {
}
@Test
public void testName() throws Exception {
verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""));
}
}
Java 8 中的错误信息如下所示:
Error:(33, 9) java: reference to verifyThat is ambiguous
both method <T>verifyThat(com.sabre.ssse.core.dsl.GenericTest.SecondGenericClass<T>,com.sabre.ssse.core.dsl.GenericTest.GenericClass<T>) in com.sabre.ssse.core.dsl.GenericTest and method <T>verifyThat(T,com.sabre.ssse.core.dsl.GenericTest.GenericClass<T>) in com.sabre.ssse.core.dsl.GenericTest match
我查看了以下之间的所有更改:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2
但我没有注意到这种行为的确切原因。
编辑:
只是回答一些 cmets,很明显,Java 7 和 8 中的编译器都能够处理此类调用(签名类似于编译时类型擦除后留下的签名:
public static void verifyThat(SecondGenericClass actual, GenericClass matcher) {
}
public static void verifyThat(Object actual, GenericClass matcher) {
}
@Test
public void testName() throws Exception {
verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""));
}
为两个泛型方法生成的字节码和擦除的字节码是相同的,看起来像这样:
public static verifyThat(Lcom/sabre/ssse/core/dsl/GenericTest$SecondGenericClass;Lcom/sabre/ssse/core/dsl/GenericTest$GenericClass;)V
public static verifyThat(Ljava/lang/Object;Lcom/sabre/ssse/core/dsl/GenericTest$GenericClass;)V
编辑2:
在 javac 1.8.0_40 下编译失败,同样的错误
【问题讨论】:
-
即使使用具体的泛型,这也是个问题
-
是的,但是根据JLS,应该选择更具体的方法
-
@xendoo 问题发生在运行时。然后,泛型类型被删除,无法确定差异/两种方法同样不具体。
-
在计算机上测试您的代码后,我在使用 Java 8u31 的 Eclipse Luna 4.4 中没有收到任何警告或错误 - picture