Tim*_*ole 30 java generics overload-resolution
我试图理解为什么编译器无法解析bar方法调用。我希望bar(Xyz::new)始终选择bar(Supplier)因为bar(T extends Xyz)由于 的上限而永远无法匹配Xyz。
public <T extends Xyz> void foo(T s) {}
public <T extends Xyz> void bar(T s) {}
public <T extends Xyz> void bar(Supplier<T> s) {}
public void example() {
    foo(Xyz::new); // not valid (does not extend Xyz)
    bar((Supplier<Xyz>) Xyz::new); // valid (explicitly a Supplier)
    bar(Xyz::new); // ambiguous - but only one method is valid?
}
public static class Xyz {}
Run Code Online (Sandbox Code Playgroud)
如果bar(T)不适用,即使单独使用(如 所示foo(T)),那么唯一的选择肯定是bar(Supplier)使其成为明确的重载。
为什么bar调用不明确,特别是当foo和bar(T)调用本身不是有效的解决方案时?
上述代码的可运行示例: https: //www.jdoodle.com/ia/kqP
Mic*_*ael 26
你是对的,更聪明的编译器应该能够明确地解决这个问题。
Java 解析方法调用的方式很复杂。它是由 JLS 定义的,我将其设置为 7500 个单词纯粹是为了确定如何解析方法。粘贴到文本编辑器中,共有 15 页。
一般的做法是:
我不明白所有细节以及它与您的具体案例有何关系。如果您想深入了解它,那么我已经链接了完整的规范。希望这个解释足以满足您的目的:
歧义性在步骤 2.6 中确定,但在步骤 3 中仍然有进一步的适当性检查。您的foo方法一定在步骤 3 处失败。您的bar方法永远不会走到那么远,因为编译器仍然认为这两种方法都是有效的可能性。人类可以确定不适当性可以解决歧义,但这并不是编译器执行操作的命令。我只能推测原因——性能可能是一个因素。
您的代码在泛型、重载和方法引用的交叉点上运行,这三者都是在不同时间引入的;编译器会遇到困难,这对我来说并不奇怪。
NoD*_*und 18
您的问题主要是类型推断问题,而不是方法不明确的问题:
public <T extends Xyz> void bar(T s) {} // bar(Xyz)
public void bar(String s) {}
public <T extends Zyx> void bar(T s) {} // bar(Zyx)
public <T extends Xyz> void bar(Supplier<T> s) {}
public static class Xyz {}
public static class Zyx {}
Run Code Online (Sandbox Code Playgroud)
如果您使用:
    bar(new Xyz());  // ok
    bar("a");   // ok
    bar(new Zyx());   // ok
    bar((Supplier<Xyz>) Xyz::new); // ok
    bar(Xyz::new); // ambiguous
Run Code Online (Sandbox Code Playgroud)
您收到此错误(使用 Java 17 尝试过),该错误与 lambda 无关,而是与类型有关T:无法推断类型变量 T
  both method <T#1>bar(T#1) in Example and method <T#2>bar(Supplier<T#2>) in Example match
  where T#1,T#2 are type-variables:
    T#1 extends Zyx declared in method <T#1>bar(T#1)
    T#2 extends Xyz declared in method <T#2>bar(Supplier<T#2>)
Example.java:18: error: incompatible types: cannot infer type-variable(s) T
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Java 不够聪明,无法找到具体类型 T,你必须帮助它:
Example.<Xyz>bar(Xyz::new);
Run Code Online (Sandbox Code Playgroud)
我试图研究由迈克尔答案驱动的 JLS,应该更好地回答你的问题的部分是 18.5.1 。调用适用性推断。
我在 Java 7 和 Collections 中经常出现同样类型的错误:
public static <T extends Zyx> void bar(java.util.List<T> s) {} // bar(Zyx)
public static <T extends Zyx> void bar(T s) {} // bar(List)
bar(new Zyx()); 
bar(java.util.Collections.emptyList()); 
Run Code Online (Sandbox Code Playgroud)
更糟糕的是 Eclipse 没有任何问题,而 javac 却失败了。
我想在 lambda 的情况下,编译器不会从“Xyz”推断出类型 T。
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           2328 次  |  
        
|   最近记录:  |