为什么以下第一个示例不起作用?
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(不是对象):
但是,如何成功编译示例怎么可能呢?
你的run
方法需要一个Runnable
实例,这就解释了为什么run(new R())
与R
实现一起工作。
R::new
不等同于new R()
。它可以适合Supplier<Runnable>
(或类似的功能接口)的签名,但R::new
不能用作与Runnable
类一起实现的R
。
你的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);
但是,你可以注意到,用Runnable
创建的R::new
只是在new R()
方法体中调用run
。
有效地使用方法引用来执行R#run
可能会使用一个实例,就像这样(但在这种情况下,你肯定会直接使用r
实例):
R r = new R();
new ConstructorRefVsNew().run(r::run);
第一个例子用法method reference from java 8:
new ConstructorRefVsNew().run(R::new);
或多或少相当于:(Java 8 lambda expression)
new ConstructorRefVsNew().run( () -> {new R();} );
效果是你只是创建一个R的实例,但不要调用它的run
方法。
比较两个电话:
((Runnable)() -> new R()).run();
new R().run();
通过((Runnable)() -> new R())
或((Runnable) R::new)
,你创造了一个新的Runnable
,什么都不做。
通过new R()
,您可以创建R
类的实例,其中run
方法是明确定义的。
1实际上,它创建了一个R
的对象,它对执行没有影响。
我想在不修改main
方法的情况下同样处理2次调用。我们需要用run(Runnable)
重载run(Supplier<Runnable>)
。
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();
}
void run(Supplier<Runnable> s) {
run(s.get());
}
static class R implements Runnable { ... }
}
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()
。没有更多,没有更少。