gpt4 book ai didi

泛型类的 Java 8 模糊方法引用

转载 作者:搜寻专家 更新时间:2023-10-30 21:27:27 26 4
gpt4 key购买 nike

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

编辑2:

在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 中,由于(编译器)寻找类型参数以使更多方法适用(也称为有限类型推断)的尝试有限,因此更容易使方法不适用。表达式 new SecondGenericClass<>("")有类型 SecondGenericClass<String>从它的论点推断""就是这样。所以对于调用verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""))参数的类型为 SecondGenericClass<String>GenericClass<String>制作方法<T> void verifyThat(T,GenericClass<T>)不适用。

请注意,有一个模棱两可的调用示例显示了 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 中正在发生的事情的提示,其中 new GenericClass<>("") 的类型固定为 GenericClass<String>就像 new GenericClass<String>("") .


最重要的是,从 Java 7 到 Java 8(显着)变化的不是最具体的方法的选择,而是改进类型推断带来的适用性。一旦这两种方法都适用,调用就会变得不明确,因为这两种方法都不比另一种方法更具体。

关于泛型类的 Java 8 模糊方法引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29493405/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com