Java 8模糊方法引用通用类

下面的代码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

但是我没有注意到这个行为的确切原因.

编辑:

只是为了回答一些意见,很清楚,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下的编译失败,出现相同的错误

解决方法

JLS,chapter §15.12.2.5 Choosing the Most Specific Method一个难读,但包含一个有趣的总结:

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 一个模糊调用的示例,其在java="" 7(甚至java="" 6)下展现了歧义):verifythat(null,null);使用javac时会引发编译器错误.="" 但是java="" 8有 Invocation Applicability Inference(我们与JLS 7有一个全新的篇章…),它允许编译器选择引用方法候选的类型参数(通过嵌套调用工作).您可以为您的特殊情况找到这样的类型参数,甚至可以找到适合两者的类型参数,

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(显着地)改变的最具体的方法的选择,而是由于改进的类型推断的适用性.一旦这两种方法都适用,调用是不明确的,因为这两种方法都不比其他方法更具体.

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...