在 Java 中使用函数接口时是否有隐式类型转换?

Is there an implicit type casting when using Functional Interfaces in Java?

提问人:DashwoodIce9 提问时间:7/24/2023 更新时间:7/24/2023 访问量:69

问:

我编写了以下 Java 代码并期望它不会编译,但它确实编译并且执行了违反直觉。我正在使用 Java 17。

TestFunctionExecutor.java

@FunctionalInterface
public interface TestFunctionExecutor{
    void execute();
}

TestClass.java

public class TestClass{
    public static void main(String... args) {
        TestClass test = new TestClass();
        test.wrapper(test::sampleFunction);
    }
    
    public void sampleFunction() {
        System.out.println("Inside sampleFunction");
    }

    public void wrapper(TestFunctionExecutor method) {
        System.out.println("Before method execution");
        method.execute();
        System.out.println("After method execution");
    }
}

输出-

Before method execution
Inside sampleFunction
After method execution

我认为,既然需要一个类型的参数,并且我正在传递一个类型的参数,那么编译应该会失败。我使用了一个调试器,看起来像是在运行时。这让我感到困惑,我有几个问题——wrapperTestFunctionExecutorTestClassmethodTestClass$$Lambda$1...

  1. 是什么类型的?不是还是类似的东西?我无法用调试器推断出这一点。test::SampleFunctionTestClassTestClass$$sampleFunction...
  2. 为什么这里没有错误?看起来这些类型以某种方式变得兼容,如何?
  3. 如何知道要执行什么代码?execute
  4. 这是好代码吗?我的目标是包装一个函数,以便一些代码在它之前和之后运行。

谢谢!

Java 反射 转换 java-17 函数接口

评论

2赞 Pshemo 7/24/2023
“由于包装器需要一个 TestFunctionExecutor 类型的参数,而我正在传递一个 TestClass 类型的参数”您不是在传递 TestClass 的实例,而是传递 lambda 的实例(类型为 TestClass$$sampleFunction...这是 的子类型 ),它正在使用 。无论如何,语法称为方法引用,但要正确掌握它,您应该从 lambda 开始。考虑阅读 lambdafaq.org docs.oracle.com/javase/tutorial/java/javaOO/...... docs.oracle.com/javase/tutorial/java/javaOO/......TestFunctionExecutorTestClass testfoo:::bar
0赞 DashwoodIce9 7/24/2023
感谢您@Pshemo资源,我将介绍它们。一个简短的问题 - 你说“是”的子类型。如何?TestClass$$sampleFunction...TestFunctionExecutor
2赞 Pshemo 7/25/2023
由于类型推断,编译器知道方法的参数必须是类型(包括其子类型)。因此,当编译器创建类时,例如 lambda 的实现或方法引用,它必须确保此类是 TestFunctionExecutor 的子类型,这意味着它(因为这是方法期望作为参数)。public void wrapper(TestFunctionExecutor method)TestFunctionExecutorTestClass$$Lambda$1...... implements TestFunctionExecutorwrapper

答:

2赞 Baptiste Beauvais 7/24/2023 #1

在 Java 中,lambda 表达式只是 Anonymous 类的一种语法,它基本上是使用 JVM 创建的名称当场创建的

您的代码可以以 4 种方式(从更简洁到更不简洁)编写:

test.wrapper(test::sampleFunction);

test.wrapper(() -> test.sampleFunction());

test.wrapper(() ->  {
   test.sampleFunction();
});

test.wrapper(new TestFunctionExecutor() {
    public void execute() {
       test.sampleFunction();
    }
});

当您使用 lambda 表达式时,您实际上是在创建一个实现函数接口的匿名类的新实例。此实现的方法包含要运行的运行。

至于最后一个问题,它可能是正确的代码,但这是一个非常广泛的主题。