【问题标题】:Reference to method is ambiguous method reference vs lambda对方法的引用是模棱两可的方法引用与 lambda
【发布时间】:2018-05-03 07:24:43
【问题描述】:

我有以下课程

接口 1

 package test;

    public interface TODO {

        boolean test();
    }

界面2

package test;

@FunctionalInterface
public interface FuncN {
  State zip(State ...states);
}

1 级

package test;

public class Test {

    public static Test define(FuncN zipperFunc,TODO... tasks) {
        return null;
    }


    public static Test define(TODO... tasks) {
        return null;
    }
}

2 级

封装测试;

public class State {
    public static State mergeStates(State ...states) {
        return null;
    }
}

主类

package test;

public class Main {
    public static void main(String[] args) {
      Test.define(State::mergeStates,()->true);
    }
}

主类没有编译,抛出错误

对定义的引用不明确 Test.define(State::mergeStates,()->true); ^ Test 中的方法 define(FuncN,TODO...) 和 Test 匹配中的方法 define(TODO...)

下面的类确实编译:

package test;

public class Main {
    public static void main(String[] args) {
      Test.define(states->State.mergeStates(states),()->true);
    }
}

但是我没有看到任何歧义。 FuncN 和 TODO 的签名完全不同,我认为编译器不应该将它们误认为是另一个。

如果我错了,请纠正我。

附注使用 eclipse 无法重现错误,因此我建议创建一个文件夹 test 在其中创建所有 java 文件并运行 javac test/Main.java

【问题讨论】:

  • 我无法复制。 Test.define(State::mergeStates,()->true); 为我通过编译。
  • 我的 jvm 规格如下: java 版本 "1.8.0_171" Java(TM) SE Runtime Environment (build 1.8.0_171-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.171- b11,混合模式)javac 1.8.0_171。它不会在 Eclipse 中引发任何错误,我建议创建一个文件夹 test 将所有文件放入其中,然后运行 ​​javac test/Main.java 这就是引发错误的方式。
  • 由于mergeState是一个varargs方法,State::mergeStates是一个不精确的方法引用,它需要目标类型得到完全解析,但是在知道将调用哪个define 方法之前,不知道目标类型,但是必须在不考虑State::mergeStates 参数的情况下做出此决定,其功能签名未知。虽然可以排除一种变体,例如通过尝试,规范不包括这样的测试(故意不进一步增加复杂性)。
  • 所以当你将目标方法设为非varargs,即public class State { public static State mergeStates(State[] states) { return null; } },错误就会消失。
  • @Holger 我不知道你为什么不回答这个问题,这又是 我们需要解析方法才能找到目标类型的情况,但我们需要知道目标类型以解析方法。我发誓每次遇到这种情况我都必须去重新阅读我的笔记

标签: java-8 javac method-reference


【解决方案1】:

如果您将方法引用调用强制转换为 FincN,它将编译。 Test 类调用“define”中有两种重载方法,因此编译器会混淆选择哪一种。所以尝试如下使用。

    public static void main(String[] args){
      Test.define((FuncN) State::mergeStates,()->true);
    }

【讨论】:

  • 同意,但我的问题是为什么首先会发生错误?由于两个接口的签名不同,因此不应发生错误。 eclipse 是如何做到的,而 javac 不是。
  • @Shariq 很可能是 Eclipse(ECJ 编译器)对此有一个错误,而 javac 是正确的
  • @Shariq 我没有使用 eclipse,所以我无法评论 eclipse 编译器。对于 'State::mergeStates' 方法参考可以用于许多功能接口,例如供应商、功能、消费者等,因此您必须强制转换并告诉您使用哪个功能。如果有很多选择可供选择
  • @Shariq 顺便说一句,作者本人在这里stackoverflow.com/a/21951311/1059372 的阅读非常好。我希望你现在明白,这是一个ECJ 错误
  • @Eugene 现在我明白 Holger 的意思了,他说“虽然可以排除一种变体,例如通过尝试,但规范不包括这样的测试(故意不增加复杂性进一步)。”感谢您的帮助,我将从您提供的链接中阅读。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
  • 2010-11-18
  • 1970-01-01
  • 2019-12-13
  • 2017-03-06
相关资源
最近更新 更多