为什么它不输出“狗吃”

voz*_*zrr 5 java constructor-reference

像这样的代码

public class LambdaTest {
    public static void main(String[] args) {
        final Animal animal = Dog::new;
        animal.eat();
    }
}

@FunctionalInterface
interface Animal {
    void eat();
}

class Dog implements Animal {

    public Dog() {
        System.out.println("dog init.");
    }

    @Override
    public void eat() {
        System.out.println("dog eat");
    }
Run Code Online (Sandbox Code Playgroud)

当我运行这段代码时,“dog init”。被打印到控制台,但“dog eat”却没有。这是为什么?有人能告诉我原因吗?

我预计会打印“dog init”和“dog eat”,但只打印了“dog init”。另外,我很困惑为什么在Animal animal = Dog::new;.

kni*_*ttl 6

Animal是一个具有单一方法void eat()(void 返回,无参数)的函数式接口 \xe2\x80\x93 也称为SAM 类型(单一抽象方法)。

\n

java.util.Runnable它在结构上与接口( )相同interface Runnable { void run(); }。你的代码也可以写成:

\n
final Runnable runnable = Dog::new;\nrunnable.run(); // calls the constructor\n
Run Code Online (Sandbox Code Playgroud)\n

您可以为其分配任何具有零参数且无返回值的 lambda 或方法引用,例如() -> {}.

\n

Dog::new是一个方法引用,相当于 lambda() -> { new Dog(); }. If you look closely, you will notice that this lambda does not return anything. It constructs a new Dog instance and then forgets about it again.

\n

将方法引用或 lambda 分配给变量并不会执行它(尚未)。您必须通过从接口调用命名方法来显式调用 lambda。

\n

现在,您animalAnimal接口的一个实例,并被分配了一个方法引用,稍后可以调用该方法引用。animal.eat() invokes the assigned method reference, calling the constructor.

\n

如果您希望变量animal保存一个Dog实例,然后调用eat它的方法,请直接调用构造函数:Animal animal = new Dog();

\n

“问题”是您的方法的签名eat,因为它相当于Runnable#run并允许分配任何“空”操作。

\n

Lambda 和方法引用是在 Java 8 中引入的。在之前的 Java 版本中,您必须创建一个匿名类才能实现相同的行为:

\n
final Animal animal = new Animal() {\n  @Override public void eat() {\n    new Dog();\n  }\n};\nanimal.eat(); // calls "eat" of the anonymous instance, which in turn calls the constructor; does NOT call `Dog#eat`\n
Run Code Online (Sandbox Code Playgroud)\n