我们有这个代码:
public class Test {
public static Object foo() {
System.out.println("Foo");
return new Object();
}
public static void main(String[] args) {
J j = Test::foo;
j.m();
}
}
interface J {
void m();
}
并且此代码将起作用。关键的一条线是
J j = Test::foo;
尽管interface J
声明它具有void
函数,但Test::foo
返回一个Object
。
虽然我们不能在实现接口时覆盖方法(这很明显(。 这仅在接口的方法void
时有效,否则代码将无法编译。有人能说出为什么它的工作方式是这样工作的吗?:D
尽管
interface J
声明它具有void
函数,但Test::foo
返回一个Object
。
说Test::foo
返回某些东西是不准确的。在不同的上下文中,它可能意味着不同的事情。
Supplier<Object> a = Test::foo;
J b = Test::foo;
Runnable c = Test::foo;
更准确地说,Test::foo
可以表示一个目标类型,其函数方法返回void
或Object
。
这是表达式语句 (jls-14.8( 的一个示例。
如果目标类型的函数类型具有
void
返回,则 lambda 主体是语句表达式(§14.8( 或与 void 兼容的块 (§15.27.2(。
...
表达式语句通过计算表达式来执行;如果表达式具有值,则丢弃该值。
我不确定到底是什么让你感到困惑,所以这里有一些其他方法可以查看你的示例。
J j = Test::foo;
可以改写为
J j = () -> Test.foo();
因为它从功能接口J
m()
提供主体到方法,并且该方法不需要任何参数(这就是为什么它以() ->
开头(。
但这可以看作是较短的版本
J j = new J(){
public void m(){
Test.foo(); //correct despite `foo` returning value
}
};
这是正确的,因为 Java 允许我们忽略被调用方法的返回值,例如在返回boolean
值的情况下List#add(E element)
,但我们仍然可以像list.add(1)
一样编写代码,而不必处理返回值。