为什么我们不能在函数式接口中重载抽象方法?(爪哇)

Cyb*_*ent 8 java oop overloading functional-interface

所以我熟悉 java 中的函数式接口,以及它们与 lambda 表达式的使用。一个函数式接口只能包含一个抽象方法。在 lambda 表达式中使用这个单独的方法时,您不需要指定它的名称 - 因为接口中只有一个抽象方法,编译器知道这是您正在引用的方法。

例子:

// Functional Interface:

@FunctionalInterface
public interface Ball
{
    void hit();
}

// Lambda to define, then run the hit method:

Ball b = () -> System.out.println("You hit it!");

b.hit();
Run Code Online (Sandbox Code Playgroud)

虽然很明显为什么一个函数式接口只能包含一个抽象方法,但我不明白为什么不能重载那个方法。

例如,以下将无法编译:

// (NOT) Functional Interface:

@FunctionalInterface
public interface Ball
{
    void hit();
    void hit(boolean miss);
}

// Lambda to define, then run the hit method:

Ball b = () -> System.out.println("You hit it!");
Ball ba = (boolean miss) -> System.out.println(miss);

b.hit();
ba.hit(false);
Run Code Online (Sandbox Code Playgroud)

编译器声明Ball接口不起作用,因为它包含多个方法,但在这种情况下,我不明白为什么会出现问题 - 只要这两个方法采用不同的参数,就应该可以推断出哪个方法我根据我定义的参数在 lambda 中引用。

有人可以解释为什么不能在函数式接口中重载抽象方法吗?

Neu*_*ron 4

在没有方法重载的语言中,方法由其在该类中的名称唯一标识(暂时忽略覆盖)。

\n

但在 Java 中情况有些不同。引用oracle文档:

\n
\n

重载方法

\n

Java编程语言支持重载方法,并且Java可以区分具有不同方法签名的方法。这意味着,如果类中的方法具有不同的参数列表,则它们可以具有相同的名称(对此有一些限制,将在标题为“接口和继承”的课程中讨论)。

\n
\n

所以我们知道方法也是通过它们的签名来识别的。如果两个方法共享一个名称但没有相同的签名,则它们是不同的方法。不要让他们的共同名字欺骗您,让您认为他们有某种联系。

\n

考虑到这一事实,我们可以轻松创建一个示例,其中如果方法的行为符合您所描述的方式,则会发生未定义的行为:

\n
Ball ba = (boolean miss) -> System.out.println(miss);\nsomeFunction(ba)\n
Run Code Online (Sandbox Code Playgroud)\n\n
public void someFunction(Ball ball) {\n    ball.hit();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下您会期望什么行为?这是未定义的!

\n
\n

您可以 \xe2\x80\x94 但是 \xe2\x80\x94 使用默认方法。我不太了解您的情况,无法判断这是否合适,但您可以这样做:

\n
@FunctionalInterface\npublic interface Ball\n{\n    default void hit() {\n        hit(true);\n    }\n\n    void hit(boolean miss);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

其工作原理在文档FunctionalInterface中进行了解释:

\n
\n

从概念上讲,函数式接口只有一个抽象方法。由于默认方法有一个实现,因此它们不是抽象的

\n
\n