是什么决定从lambda创建哪个功能接口?

Win*_*ter 5 java lambda java-8 functional-interface

请考虑这个例子:

import java.util.function.Consumer;

public class Example {
    public static void main(String[] args) {
        Example example = new Example();

        example.setConsumer(test -> System.out.println("passed string is " + test)); //uses MyConsumer, why ?
        example.getConsumer().accept("Test 1");

        example.setConsumer((MyConsumer<String>)test -> System.out.println("passed string is " + test)); //uses MyConsumer
        example.getConsumer().accept("Test 2");

        example.setConsumer((Consumer<String>)test -> System.out.println("passed string is " + test)); //uses Consumer
        example.getConsumer().accept("Test 3");
    }

    private Consumer<String> consumer;

    public Consumer<String> getConsumer() {
        return consumer;
    }

    public void setConsumer(Consumer<String> consumer) {
        this.consumer = consumer;
    }

    public void setConsumer(MyConsumer<String> consumer) {
        this.consumer = consumer;
    }

    @FunctionalInterface
    public interface MyConsumer<T> extends Consumer<T> {
        @Override
        default void accept(T value) {
            System.out.println("In consumer string: " + value); //example thing to do
            receive(value);
        }

        void receive(T value);
    }
}
Run Code Online (Sandbox Code Playgroud)

我最感兴趣的是第一次测试.为什么使用MyConsumer而不是Consumer?如果我有更多不同的消费者具有相同的lambda结构,谁具有优先权呢?另外,我在测试2上进行的演员表Redundant由我的IDE 标记.这意味着lamdba首先被创建为MyConsumer.为什么这样 ?

我正在使用IntelliJ Idea和Javac.

man*_*uti 6

它是根据选择语言规范定义的最具体方法的过程:

如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符.Java编程语言使用选择最具体方法的规则.

...

如果T不是S的子类型且下列之一为真,则功能接口类型S 比表达式e的功能接口类型T 更具体(其中U1 ... Uk和R1是参数类型和返回类型捕获S的函数类型,V1 ... Vk和R2是T)函数类型的参数类型和返回类型:

  • 如果e是显式类型的lambda表达式(第15.27.1节),则以下之一为真:
  • R2无效.

  • R1 <:R2.

  • R1和R2是功能接口类型,并且对于e的每个结果表达式,存在至少一个结果表达式,并且R1比R2更具体.

    (具有块体的lambda表达式的结果表达式在§15.27.2中定义;具有表达式主体的lambda表达式的结果表达式就是主体本身.)

  • R1是基本类型,R2是引用类型,并且至少有一个结果表达式,e的每个结果表达式是基本类型的独立表达式(第15.2节).

  • R1是引用类型,R2是基本类型,并且至少有一个结果表达式,e的每个结果表达式都是引用类型的独立表达式或多义表达式.

  • 如果e是精确的方法参考表达式(§15.13.1),则i)对于所有i(1≤i≤k),Ui与Vi相同,并且ii)以下之一为真:
  • R2无效.

  • R1 <:R2.

  • R1是基本类型,R2是引用类型,方法引用的编译时声明具有返回类型,它是基本类型.

  • R1是引用类型,R2是基本类型,方法引用的编译时声明具有返回类型,它是引用类型.

  • 如果e是带括号的表达式,则这些条件之一递归地应用于包含的表达式.

  • 如果e是条件表达式,则对于第二和第三操作数中的每一个,递归地应用这些条件之一.

因此,MyConsumer更具体的是Consumer因为Consumer(T在规范中)不是子类型并且都具有返回值void.