Почему мы не можем перегрузить абстрактный метод в функциональном интерфейсе?(Джава) - PullRequest
0 голосов
/ 28 февраля 2019

Итак, я знаком с функциональными интерфейсами в Java и их использованием с лямбда-выражениями.Функциональный интерфейс может содержать только один абстрактный метод.При использовании этого одинокого метода из лямбда-выражения вам не нужно указывать его имя - поскольку в интерфейсе есть только один абстрактный метод, компилятор знает, что это метод, на который вы ссылаетесь.

Пример:

// 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 не функционален, поскольку содержит более одного метода, но в этом случае я не понимаюпочему это может быть проблемой - поскольку эти два метода принимают разные параметры, можно определить, какой метод я ссылаюсь в лямбда-выражении, исходя из того, какие параметры я определяю.

Может кто-тообъяснить, почему невозможно перегрузить абстрактный метод в функциональном интерфейсе?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Пока вы объявляете класс, который реализует интерфейс Ball, вы должны реализовывать все абстрактные методы.Например, если вы сделаете это следующим образом:

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

, тогда вы передадите b в качестве параметра, а другой код вызовет b.hit(true), он сломается, потому что hit(boolean miss) не реализовано.

Таким образом, функциональный интерфейс должен иметь только один абстрактный метод.

0 голосов
/ 28 февраля 2019

В языках без перегрузки методов методы однозначно идентифицируются по имени в этом классе (на данный момент игнорируя переопределение).

В Java все немного по-другому.Цитирование из oracle docs :

Методы перегрузки

Язык программирования Java поддерживает методы перегрузки, и Java может различать методы с помощьюподписи разных методов.Это означает, что методы в классе могут иметь одно и то же имя, если они имеют разные списки параметров (есть некоторые уточнения к этому, которые будут обсуждаться в уроке под названием «Интерфейсы и наследование»).

Итакмы знаем, что методы также идентифицируются по их подписи.Если два метода имеют общее имя, но не имеют одинаковую сигнатуру, это разные методы .Не позволяйте их общему имени вводить вас в заблуждение, думая, что они каким-то образом связаны.

Учитывая этот факт, мы можем легко создать пример, в котором неопределенное поведение могло бы произойти, если бы методы вели себя так, как вы описали:

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

Какое поведение вы ожидаете в этом случае?Это не определено!


Вы можете - однако - использовать методы по умолчанию .Я не знаю вашу ситуацию достаточно хорошо, чтобы судить, подходит ли этот подход, но вы можете сделать это:

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

    void hit(boolean miss);
}

Почему это объясняется в документации для FunctionalInterface:

Концептуально функциональный интерфейс имеет ровно один абстрактный метод.Поскольку методы по умолчанию имеют реализацию, они не являются абстрактными

...