Есть ли способ перегрузить абстрактный метод в функциональном интерфейсе?

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

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

Я хотел бы иметь возможность написать что-то вроде следующего кода:

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

b.hit();
b.hit(false);
ba.hit();
ba.hit(false);

Желаемый результат:

You hit it!
default false
default hit
false

Рассмотрим следующий (не компилируемый) код (в основном скопированный из связанного вопроса):

@FunctionalInterface
public interface Ball
{
    void hit();
    void hit(boolean miss);
    default void hit(){
        System.out.println("default hit");
    }
    default void hit(boolean miss){
        System.out.println("default" + miss);
    }

}

Я ищу альтернативу этому коду, который будет компилироваться.

Функциональный интерфейс допускает только один абстрактный метод. Как вы ожидаете, что это сработает?

ernest_k 30.05.2019 19:32

Обратите внимание, что у вас не может быть двух определений метода в интерфейсе, даже если одно из них абстрактное, а другое используется по умолчанию. Вы пробовали компилировать свой код? Не думаю, что он скомпилируется. @Йехуда

Kartik Soneji 30.05.2019 19:33

@KartikSoneji Как было написано в вопросе, код не компилируется. Я ищу способ создать что-то эквивалентное.

Yehuda Rimon 30.05.2019 19:35
stackoverflow.com/q/25299653/2711488stackoverflow.com/q/21833537/2711488 (обратите внимание на ответы под принятым)
Holger 31.05.2019 12:26
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
140
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Таким образом, ответ на 100% невозможен, и ваш код выше получит ошибку компиляции, поскольку вы сохранили аннотацию @FunctionalInterface, которая строго запрещает хранить более одного абстрактного метода. Согласно вашему коду

@FunctionalInterface
public interface MyInter {
    public abstract void fly();

    public abstract void fly(int a);

    default void fly() {}          \\line1
    default void fly(int g) {   }   \\line2
}

строки 1 и 2 вызовут ошибку времени компиляции, так как java видит их по имени метода одинаковым и типам аргументов одинаковым, они никогда не будут беспокоиться о возвращаемом типе или значении по умолчанию или т. д. (основное правило перегрузки).

более того, если удалить строки 1 и 2, код тоже выдаст ошибку, потому что @functionalinterface выдаст ошибку компиляции с указанием недопустимая аннотация @FunctionalInterface; MyInter не является функциональным интерфейсом.

Надеюсь, что это ответ на ваш вопрос...

Вы могли бы сделать что-то вроде этого. Но вам нужно будет правильно назвать свои переменные, чтобы отслеживать как arg, так и consumer, которые их принимают.

@FunctionalInterface
interface Ball<T> {
   void hit();

   static <T> Ball<T> withArg(T arg, Consumer<T> com) {
      return () -> com.accept(arg);
   }
}

public class Demo {
   public static void main(String[] args) {
      Ball<Boolean> b = () -> System.out.println("You Hit it!");
      b.hit();
      Ball<Boolean> ba = Ball.withArg(false, a -> System.out.println(a));
      Ball<Boolean> bb = Ball.withArg(true, a -> System.out.println(a));
      ba.hit();
      bb.hit();
   }
}
Ответ принят как подходящий

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

Пример кода:

public class Test{
    public static void main(String... args) throws Exception{
        Ball b = new Ball(() -> System.out.println("You hit it!"));
        Ball ba = new Ball((boolean miss) -> System.out.println(miss));

        b.hit();
        b.hit(false);
        ba.hit();
        ba.hit(false);
    }

    public static class Ball{
        final Hit a;
        final HitBoolean b;
        
        public Ball(Hit a){
            this.a = a;
            b = (miss) -> System.out.println("default " + miss);
        }
        
        public Ball(HitBoolean b){
            this.b = b;
            a = () -> System.out.println("default hit");
        }
        
        public void hit(){
            a.hit();
        }
        
        public void hit(boolean miss){
            b.hit(miss);
        }
    }

    public interface Hit{
        void hit();
    }
    
    public interface HitBoolean{
        void hit(boolean miss);
    }
}

Вывод программы:

You hit it!
default false
default hit
false

Другие вопросы по теме