Runnable :: new vs new Runnable()

问题描述 投票:60回答:4

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

  • 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(不是对象):

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

java java-8 runnable constructor-reference
4个回答
57
投票

你的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);

22
投票

第一个例子用法method reference from java 8

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

或多或少相当于:(Java 8 lambda expression

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

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


9
投票

比较两个电话:

((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 { ... }
}

7
投票

run方法需要一个Runnable

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

但是当你通过R::new时,其他事情正在发生。你告诉它的是创建一个与Runnable兼容的匿名对象,其run方法运行你传递的操作。

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

new Runnable() {

     public void run() {
         new R();
     }
}

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

R::new,在被叫时,叫new R()。没有更多,没有更少。

© www.soinside.com 2019 - 2024. All rights reserved.