Runnable :: new vs new Runnable()

use*_*245 61 java runnable java-8 constructor-reference

为什么以下第一个示例不起作用?

  • 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");
      }
  }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

  R constructor runs
  -----------------------
  R constructor runs
  R.run runs
Run Code Online (Sandbox Code Playgroud)

在第一个示例中,R调用构造函数,它返回lambda(不是对象):

但是,如何成功编译示例怎么可能呢?

ern*_*t_k 56

您的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();
}
Run Code Online (Sandbox Code Playgroud)

为什么编译?

因为编译器可以进行Runnable构造函数调用,这相当于这个lambda表达式版本:

new ConstructorRefVsNew().run(() -> {
    new R(); //discarded result, but this is the run() body
});
Run Code Online (Sandbox Code Playgroud)

这些陈述同样适用:

Runnable runnable = () -> new R();
new ConstructorRefVsNew().run(runnable);
Runnable runnable2 = R::new;
new ConstructorRefVsNew().run(runnable2);
Run Code Online (Sandbox Code Playgroud)

但是,正如您所注意到的,Runnable创建的R::new只是调用new R()run方法体.


对执行方法引用的有效使用R#run可以使用像这样的实例(但r在这种情况下,你肯定会直接使用实例):

R r = new R();
new ConstructorRefVsNew().run(r::run);
Run Code Online (Sandbox Code Playgroud)

  • @ user1722245我编辑了答案。在这种情况下,编译器由R :: new制成`()-&gt; {new R();}`。 (2认同)

Hen*_*nry 23

第一个例子:

new ConstructorRefVsNew().run(R::new);
Run Code Online (Sandbox Code Playgroud)

或多或少相当于:

new ConstructorRefVsNew().run( () -> {new R();} );
Run Code Online (Sandbox Code Playgroud)

效果是您只需创建R的实例,但不要调用其run方法.

  • 这意味着,我有两个嵌套的runnable.在第一个方法上,仅调用run. (2认同)

And*_*lko 10

比较两个电话:

((Runnable)() -> new R()).run();
new R().run();
Run Code Online (Sandbox Code Playgroud)

通过((Runnable)() -> new R())((Runnable) R::new),您创建一个新的Runnable,什么也不做1.

通过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 Code Online (Sandbox Code Playgroud)


Rea*_*tic 7

run方法需要一个Runnable.

容易的情况是new R().在这种情况下,您知道结果是类型的对象R.R它本身是一个可运行的,它有一个run方法,这就是Java看到它的方式.

但是当你传递R::new其他东西时正在发生.你告诉它的是创建一个与a 方法兼容的匿名对象,Runnablerun方法运行你传递它的操作.

你通过它的操作不是Rrun方法.操作是的结构R.因此,就像你已经传递了一个匿名类,如:

new Runnable() {

     public void run() {
         new R();
     }
}
Run Code Online (Sandbox Code Playgroud)

(并非所有细节都相同,但这是最接近的"经典"Java构造).

R::new,当被叫时,打电话new R().没有更多,没有更少.