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
但是我没有注意到这个行为的确切原因.
编辑:
只是为了回答一些意见,很清楚,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
EDIT2:
javac 1.8.0_40下的编译失败,出现相同的错误
解决方法
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
我们可以轻易地为您的案例反驳,具体如下:
GenericTest.<String>verifyThat( // invokes the first method new SecondGenericClass<>(""),new GenericClass<>("")); GenericTest.<SecondGenericClass<String>>verifyThat( // invokes the second new SecondGenericClass<>(""),new GenericClass<>(null));
所以这里没有最具体的方法,但是,如示例所示,可以使用使其他方法不适用的参数来调用任一方法.
在Java 7中,由于编译器尝试(参见编译器)有限的寻找类型参数以使更多方法适用(也称为有限类型推断),因此更容易使方法不适用.新的SecondGenericClass(“”)表达式具有SecondGenericClass< String>从它的论证推断“”就是这样.因此,对于调用verifyThat(new SecondGenericClass(“”),新的GenericClass(“”)),参数的类型为SecondGenericClass< String>和GenericClass< String>这使得方法< T> void verifyThat(T,GenericClass
GenericTest.<Object>verifyThat(new SecondGenericClass<>(""),new GenericClass<>(""));
毫无疑问(在Java 8中),即使Eclipse也同意这一点.相反,调用
verifyThat(new SecondGenericClass<>(""),new GenericClass<String>(""));
具体足以使第二种方法不适用并调用第一种方法,这给我们提供了一个关于Java 7中发生的情况的提示,其中新的GenericClass(“”)的类型被固定为GenericClass< String>就像新的GenericClass< String>(“”).
底线是,它不是从Java 7到Java 8(显着地)改变的最具体的方法的选择,而是由于改进的类型推断的适用性.一旦这两种方法都适用,调用是不明确的,因为这两种方法都不比其他方法更具体.