Runnable::new vs new Runnable()

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

  • 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

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

但是,这怎么可能成功编译该示例呢?


答案 1

您的方法采用一个 Runnable 实例,这就解释了为什么与该实现一起使用。runrun(new R())R

R::new不等效于 。它可以适合(或类似的功能接口)的签名,但不能用作随类一起实现的 Runnablenew R()Supplier<Runnable>R::newR

可以采用的方法版本可能如下所示(但这将不必要地复杂):runR::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::newnew R()run


有效使用要执行的方法引用可以使用实例,如下所示(但在这种情况下,您肯定更愿意直接使用该实例):R#runr

R r = new R();
new ConstructorRefVsNew().run(r::run);

答案 2

第一个示例:

new ConstructorRefVsNew().run(R::new);

或多或少等同于:

new ConstructorRefVsNew().run( () -> {new R();} );

效果是你只是创建一个R的实例,但不调用它的方法。run


推荐