【问题标题】:Why can't we overload a abstract method in a functional interface? (Java)为什么我们不能在函数式接口中重载抽象方法? (爪哇)
【发布时间】:2019-02-28 01:13:10
【问题描述】:

所以我熟悉 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();

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

例如,以下将无法编译:

// (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);

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

谁能解释为什么不能在函数式接口中重载抽象方法?

【问题讨论】:

  • 因为如果你这样做,现在有两个抽象方法,而一个函数式接口必须有正好一个抽象方法。重载的方法彼此完全不同,它们只是碰巧共享一个名称。
  • 他们可以被区分。它们不同的。因此它们是不同的。不一样。不止一个,违反了功能接口的“完全一个”要求。
  • 两个重载的方法需要两个方法体(实现)。函数式接口必须是可以完全使用单个方法体实现的接口,然后可以使用 Lambda 语法或方法引用语法来实现。
  • “您尝试从 lambda 引用哪个”。你完全没有抓住重点。这不是关于使用(又名引用)接口。它是关于实现接口的。见我的previous comment
  • @Andreas - 天哪。你是对的,我想我有点忘了 lambda 表达式实际上在做什么

标签: java oop overloading functional-interface


【解决方案1】:

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

不过,Java 中的情况有些不同。引用自oracle docs

重载方法

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

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

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

Ball ba = (boolean miss) -> System.out.println(miss);
someFunction(ba)
public void someFunction(Ball ball) {
    ball.hit();
}

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


但是,您可以使用 default methods。我不太了解您的情况,无法判断这是否是一种合适的方法,但您可以这样做:

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

    void hit(boolean miss);
}

documentation for FunctionalInterface 中解释了这个工作原理:

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

【讨论】:

  • 是的。这就说得通了。我并没有考虑可以使用函数式接口和 lambda 表达式的所有上下文。
  • @Cyber​​_Agent 很高兴听到这个消息。我在答案的末尾添加了一个有趣的选项,可能会对您有所帮助
  • 哦,我从没想过这种方法。这实际上确实实现了我想象的行为。谢谢!
【解决方案2】:

只要你声明一个实现Ball接口的类,你就必须实现所有的抽象方法。 例如,如果你这样做:

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

那你把b作为参数传进去,其他代码调用b.hit(true),就会崩溃,因为hit(boolean miss)没有实现。

所以一个函数式接口必须只有一个抽象方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 2022-10-16
    • 1970-01-01
    相关资源
    最近更新 更多