Java 8 对方法的引用与lambda的方法引用不明确

Java 8 对方法的引用与lambda的方法引用不明确,java-8,javac,method-reference,Java 8,Javac,Method Reference,我有以下课程 接口1 package test; public interface TODO { boolean test(); } 接口2 package test; @FunctionalInterface public interface FuncN { State zip(State ...states); } 第一类 package test; public class Test { public static Test de

我有以下课程

接口1

 package test;

    public interface TODO {

        boolean test();
    }
接口2

package test;

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

package test;

public class Test {

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


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

包装试验

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);
    }
}
类main未编译,抛出错误

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

下面的类不编译:

package test;

public class Main {
    public static void main(String[] args) {
      Test.define(states->State.mergeStates(states),()->true);
    }
}
然而,我看不出任何含糊不清的地方。FuncN和TODO的签名完全不同,我认为编译器不应该把它们错当成另一个

如果我错了,请纠正我


p.S.错误在使用eclipse时是不可复制的,因此我建议创建一个文件夹测试,在其中创建所有java文件,并运行javac test/Main.java

如果将方法引用调用转换为FincN,它将编译。测试类调用“define”中有两个重载方法,所以编译器无法选择哪一个。因此,请尝试使用以下方法

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

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

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


我不能复制<代码>测试.定义(State::mergeStates,()->true)为我通过编译。我的jvm规范如下:java版本“1.8.0_171”java(TM)SE运行时环境(build 1.8.0_171-b11)java热点(TM)64位服务器VM(build 25.171-b11,混合模式)javac 1.8.0_171。它不会在eclipse中引发任何错误,我建议创建一个文件夹测试,将所有文件放入其中,然后运行javac test/Main.java这就是引发错误的方式。由于
mergeState
是一个varargs方法,
State::mergeStates
是一个不精确的方法引用,需要完全解析目标类型,但是,在知道将调用哪个
define
方法之前,目标类型是未知的,但是必须在不考虑
State::mergeStates
参数的情况下做出此决定,该参数的函数签名是未知的。虽然可以排除一个变量,例如通过尝试,但规范不包括这样的测试(故意地,为了不进一步增加复杂性)。因此,当您将目标方法设置为非varargs时,即
公共类状态{public State mergeStates(State[]states){return null;}
,错误会消失。@Holger我不知道你为什么不回答这个问题,这又是一种情况,我们需要解析方法才能找到目标类型,但我们需要知道目标类型才能解析方法。我发誓每次我遇到这个我都必须去重新阅读我的笔记,我无法复制<代码>测试.定义(State::mergeStates,()->true)为我通过编译。我的jvm规范如下:java版本“1.8.0_171”java(TM)SE运行时环境(build 1.8.0_171-b11)java热点(TM)64位服务器VM(build 25.171-b11,混合模式)javac 1.8.0_171。它不会在eclipse中引发任何错误,我建议创建一个文件夹测试,将所有文件放入其中,然后运行javac test/Main.java这就是引发错误的方式。由于
mergeState
是一个varargs方法,
State::mergeStates
是一个不精确的方法引用,需要完全解析目标类型,但是,在知道将调用哪个
define
方法之前,目标类型是未知的,但是必须在不考虑
State::mergeStates
参数的情况下做出此决定,该参数的函数签名是未知的。虽然可以排除一个变量,例如通过尝试,但规范不包括这样的测试(故意地,为了不进一步增加复杂性)。因此,当您将目标方法设置为非varargs时,即
公共类状态{public State mergeStates(State[]states){return null;}
,错误会消失。@Holger我不知道你为什么不回答这个问题,这又是一种情况,我们需要解析方法才能找到目标类型,但我们需要知道目标类型才能解析方法。我发誓每次遇到这个问题我都要去重新阅读我的笔记,我同意,但我的问题是为什么会出现这个错误?由于两个接口的签名不同,因此不应发生错误。eclipse是如何做到这一点的,而javac不是。@Shariq很可能eclipse(
ECJ
compiler)对此有缺陷,而
javac
是correct@Shariq我没有使用eclipse,因此无法对eclipse编译器进行评论。对于'State::mergeStates'方法,引用可用于许多功能接口,如供应商、函数、消费者等,因此您必须转换并告知您使用的函数。如果有很多选择available@Shariq顺便说一句,作者自己在这里读了一篇非常好的文章。我希望您现在理解,这是一个
ECJ
bug@Eugene现在我明白了霍尔格的意思,他说“虽然可以排除一种变体,例如,通过尝试,规范不包括这样的测试(故意,不进一步增加复杂性)。”感谢您的帮助,我将从您提供的链接中阅读。同意,但我的问题是,为什么会出现错误?由于两个接口的签名不同,因此不应发生错误。eclipse是如何做到这一点的,而javac不是。@Shariq很可能eclipse(
ECJ
compiler)对此有缺陷,而
javac
是correct@Shariq我没有使用eclipse,因此无法对eclipse编译器进行评论。对于'State::mergeStates'方法,引用可用于许多功能接口,如供应商、函数、消费者等,因此您必须转换并告知您使用的函数。如果有很多选择available@Shariq顺便说一句,作者自己在这里读了一篇非常好的文章。我希望您现在明白,这是一个