为什么下面的第一个例子不起作用?
run(R::new);方法R.run。run(new R());方法R.run 被调用。这两个例子都是可编译的。
public class ConstructorRefVsNew {
public static void main(String[] args) {
new ConstructorRefVsNew().run(R::new);
System.out.println("-----------------------");
new ConstructorRefVsNew().run(new R());
}
void run(Runnable r) {
r.run();
}
static class R implements Runnable {
R() {
System.out.println("R constructor runs");
}
@Override
public void run() {
System.out.println("R.run runs");
}
}
}产出如下:
R constructor runs
-----------------------
R constructor runs
R.run runs在第一个示例中,调用R构造函数,它返回lambda (它不是对象):

但是,如何才能成功地编译这个示例呢?
发布于 2019-01-07 10:18:34
您的run方法接受一个Runnable实例,这解释了为什么run(new R())与R实现一起工作。
R::new不等同于new R()。它可以适合Supplier<Runnable> (或类似的功能接口)的签名,但R::new不能用作用R类实现的Runnable。
可以接受run的R::new方法的版本可能如下所示(但这可能是不必要的复杂):
void run(Supplier<Runnable> r) {
r.get().run();
}它为什么要编译?
因为编译器可以利用构造函数调用生成一个Runnable,这相当于这个lambda表达式版本:
new ConstructorRefVsNew().run(() -> {
new R(); //discarded result, but this is the run() body
});同样的情况也适用于这些声明:
Runnable runnable = () -> new R();
new ConstructorRefVsNew().run(runnable);
Runnable runnable2 = R::new;
new ConstructorRefVsNew().run(runnable2);但是,您可以注意到,使用R::new创建的R::new只在其run方法体中调用new R()。
有效地使用方法引用来执行R#run可以使用这样的实例(但在本例中,您肯定更希望直接使用r实例):
R r = new R();
new ConstructorRefVsNew().run(r::run);发布于 2019-01-07 10:23:11
第一个例子:
new ConstructorRefVsNew().run(R::new);大致相当于:
new ConstructorRefVsNew().run( () -> {new R();} );其结果是,您只创建一个R的实例,但不调用它的run方法。
发布于 2019-01-07 10:24:55
run方法需要一个Runnable。
简单的例子是new R()。在这种情况下,您知道结果是一个R类型的对象。R本身是一个可运行的,它有一个run方法,这就是Java对它的看法。
但是当你通过R::new的时候,其他的事情正在发生。您告诉它的是创建一个与Runnable兼容的匿名对象,该对象的run方法运行您传递的操作。
您传递的操作不是R的run方法。该操作是R的构造函数。因此,就像您传递了一个匿名类,如下所示:
new Runnable() {
public void run() {
new R();
}
}(并非所有细节都相同,但这是最近的“经典”Java构造)。
R::new,当被调用时,调用new R()。没有更多,没有更少。
https://stackoverflow.com/questions/54072359
复制相似问题