当前位置: 首页 > 知识库问答 >
问题:

用泛型和lambdas重载方法时方法调用不明确

景嘉志
2023-03-14
  public <T> void test(T t) { }

  public <T> void test(Supplier<T> t) { }

  public void test() {
    test("test");
    test(() -> "test");
  }
  public <T> void test(Class<T> c, T t) { }

  public <T> void test(Class<T> c, Supplier<T> t) { }

  public void test() {
    test(String.class, "test");
    test(String.class, () -> "test"); // this line does not compile
  }

这怎么可能呢?为什么添加另一个参数会导致方法解析不明确?为什么在第一个例子中它可以区分供应商和对象,而在第二个例子中却不能?

编辑:这使用的是1.8.0_121。这是完整的错误消息:

error: reference to test is ambiguous
    test(String.class, () -> "test");
    ^
  both method <T#1>test(Class<T#1>,T#1) in TestFoo and method <T#2>test(Class<T#2>,Supplier<T#2>) in TestFoo match
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>test(Class<T#1>,T#1)
    T#2 extends Object declared in method <T#2>test(Class<T#2>,Supplier<T#2>)
/workspace/com/test/TestFoo.java:14: error: incompatible types: cannot infer type-variable(s) T
    test(String.class, () -> "test");
        ^
    (argument mismatch; String is not a functional interface)
  where T is a type-variable:
    T extends Object declared in method <T>test(Class<T>,T)

共有1个答案

呼延承平
2023-03-14

如果我对JLS for Java SE 8第15章和第18章的理解是正确的,那么您的问题的关键在于以下15.12.2段的引文:

某些包含隐式类型的lambda表达式(§15.27.1)或不精确方法引用(§15.13.1)的参数表达式被适用性测试忽略,因为在选择目标类型之前无法确定它们的含义。

当Java编译器遇到诸如test(()->“test”)之类的方法调用表达式时,它必须搜索可访问(可见)和可应用(即具有匹配签名)的方法,该方法调用可以被调度到这些方法。在第一个示例中, void test(T) void test(supplier ) 都是可访问和适用的w.r.T。test(()->“test”)方法调用。在这种情况下,当有多个匹配方法时,编译器会尝试确定最具体的一个。现在,虽然对泛型方法的确定(如JLS 15.12.2.5和JLS 18.5.4所述)相当复杂,但我们可以使用15.12.2.5开篇的直觉:

    null
    null

若k≠n,则该方法不适用,无需进行推理。

否则,对于所有i(1≤i≤k),其中e_i与适用性有关,C包括

和JLS 15.12.2.2:

    null
 类似资料:
  • 问题内容: 我注意到使用泛型和lambda重载方法的行为很奇怪。这个课程效果很好: 没有模棱两可的方法调用。但是,将其更改为此将使第二个调用不明确: 怎么会这样?为什么添加另一个参数会导致方法解析不明确?为什么在第一个示例中却能分辨出Supplier和Object之间的区别,而在第二个示例中却不能呢? 编辑:这是使用1.8.0_121。这是完整的错误消息: 问题答案: 如果我对JSE for Ja

  • 我有一个Foo和Bar对象的列表,以及每个相应对象的转换器。 Convert-method需要有所不同,因为Bar1与Bar2和Bar3等有很大不同,但是我想创建一个方法来处理所有可能的列表。 是否可以创建一个泛型方法,根据列表的内容调用相应的非泛型方法? 到目前为止,我已经尝试过了: 但这并不能编译,因为"无法解析方法'Converts(T, S)'" 有什么想法吗?

  • 我一直在尝试泛型,很快我就遇到了一些我无法解释的事情 例如: 我不明白

  • 安吉丽卡·兰格(Angelica Langer)在关于仿制药的常见问题解答中说(参见Technicalities.FAQ822): 如果这些方法具有具有不同边界的类型参数,则它们不会重写,因为这些方法的签名不是重写等价的。请记住,类型参数边界是泛型方法签名的一部分。 示例(泛型子类型方法重载泛型超类型方法;不推荐): 我不明白为什么方法在类中重载。据我所知,这应该是一个编译时错误,因为在和中具有相

  • 我有Java8 Groovy 2.4.12和下面的代码编译和运行。 但是如果你注释掉< code>return,编译器会说 此外,如果您注释掉值分配,那么它又可以了。因此,下面的代码编译并运行: 这似乎是一种特殊情况,只有在以下情况下才会发生: 注释 具有两个参数的泛型方法;第一个是泛型类型,第二个是相同泛型类型的接口 调用该泛型方法,第二个参数作为闭包,全部包装在另一个闭包中。 调用前的变量声明

  • 问题内容: 我遇到了一个涉及静态泛型方法的奇怪情况。这是代码: 我为什么不必在表达式中指定任何类型参数?这是某种类型推断吗?如果我想对此进行明确说明,如何指定类型参数? 问题答案: 是的,根据JLS第15.12.2.8节,这是基于分配目标的类型推断。明确地说,您可以这样称呼: