请考虑这个例子:
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);
}
}
我感兴趣的是第一次测试。为什么使用MyConsumer而不是Consumer?如果我有更多不同的可能的消费者具有相同的lambda结构,谁具有优先权呢?另外,我在测试2上执行的演员阵容被我的IDE标记为Redundant
。这意味着lamdba首先被创建为MyConsumer。为什么这样?
我正在使用IntelliJ Idea和Javac。
答案 0 :(得分:6)
根据语言规范定义的choosing the most specific method程序:
如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符。 Java编程语言使用选择最具体方法的规则。
...
如果T不是S的子类型且以下之一为真,则函数接口类型S对于表达式e的函数接口类型T 更具体(其中U1 ... Uk和R1是S的捕获函数类型的参数类型和返回类型,V1 ... Vk和R2是T)函数类型的参数类型和返回类型:
- 如果e是显式类型的lambda表达式(第15.27.1节),则以下之一为真:
R2无效。
R1&lt;: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)以下之一为真: / LI>
R2无效。
R1&lt;:R2。
R1是基本类型,R2是引用类型,方法引用的编译时声明具有返回类型,它是基本类型。
R1是引用类型,R2是基本类型,方法引用的编译时声明具有返回类型,它是引用类型。
如果e是带括号的表达式,则其中一个条件以递归方式应用于包含的表达式。
如果e是条件表达式,则对于第二个和第三个操作数中的每一个,递归地应用其中一个条件。
因此,MyConsumer
比Consumer
更具体,因为Consumer
(规范中的T
)不是子类型,且返回值均为{{1} }。