Java 8模糊方法引用通用类

前端之家收集整理的这篇文章主要介绍了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(显着地)改变的最具体的方法的选择,而是由于改进的类型推断的适用性.一旦这两种方法都适用,调用是不明确的,因为这两种方法都不比其他方法更具体.

猜你在找的Java相关文章