Как мне правильно ограничить общий интерфейс для расширения класса Number в Java и иметь возможность запускать его в другом классе?

#java #generics #interface #extends #subtyping

#java #дженерики #интерфейс #расширяет #подтипы

Вопрос:

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

 public interface Computable <T extends Number>
{
    public T compute(T x, T y);    
}

------------------------------------------------------------

public class TestComputable
{
    public static void main(String[] args)
    {
        Computable<Float> comp;
        comp = (x, y) -> x   y;
        printResult(comp);
    }
}

public static void printResult(Computable compIn)
{
    System.out.println("The result is: "   compIn.compute(10, 5));
}
 

Комментарии:

1. «Это работает только для целых чисел» это будет потому, что вы передаете ему целочисленные параметры.

2. @AndyTurner Даже если я изменю его на 10.1 и 5.2, результат будет тот же. Он выдает ту же ошибку. Знаете ли вы, что когда неправильно? Он не работает с Float.

Ответ №1:

Вот где компилятор действительно пытался вам помочь, выдав предупреждение об использовании необработанного типа: если вы измените printResult метод на использование правильного аргумента типа следующим образом:

 public static void printResult(Computable<Float> compIn) { // instead of Computable compIn
 

тогда компилятор выдал бы ошибку во время компиляции:

 // Now the compiler throws error:
// the method compute(Float, Float) is not applicable for the arguments (int, int)
System.out.println("The result is: "   compIn.compute(10, 5));
 

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

Теперь, когда у нас есть сообщение об ошибке компиляции, мы знаем, в чем проблема: аргументы 10 и 5 являются int значениями, в то время как интерфейс Computable ожидает Float значения, поэтому вы можете исправить их, чтобы они обрабатывались как значения с плавающей запятой:

 System.out.println("The result is: "   compIn.compute(10f, 5f));
 

Комментарии:

1. @M Anouti Есть ли способ изменить метод таким образом, чтобы компилятор мог делать выводы и выбирать правильный тип данных для выполнения?

2. @JinYuChan Проблема в том, что компилятор может видеть только 10 и 5 как Integer , в то время как вы ожидаете Float аргумент типа as . Поэтому вы должны использовать 10f and 5f . Это либо то, либо другое 🙂

Ответ №2:

Ваш код будет работать только для Integer, потому что вы передаете целочисленные аргументы вычислимому.

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

 public static <T extends Number> void printResult(Computable<T> compIn, Function<? super Integer, ? extends T> fn)
{
    System.out.println("The result is: "   compIn.compute(fn.apply(10), fn.apply(5)));
}
 

и вызывайте, как:

 printResult(comp, Integer::floatValue);
 

Кроме того, вы можете явно передать правильно введенные аргументы:

 public static <T extends Number> void printResult(Computable<T> compIn, T a, T b) {
    // ... Something with compln.compute(a, b)
}
 

и вызывайте, как:

 printResult(comp, 10.f, 5.f);
 

Единственный способ заставить это работать без передачи дополнительных параметров — это принимать только a Computable , который может принимать любое число или, по крайней мере, который может принимать аргументы типа, который вы передаете:

 public static void printResult(Computable<Number> compIn) { ... }
public static void printResult(Computable<Integer> compIn) { ... }
public static void printResult(Computable<? super Integer> compIn) { ... }
 

Комментарии:

1. Хммм, можно ли изменить метод для определения типа при передаче comp в printResult?

2. Спасибо за различные решения. Я думаю, я не могу сделать это аналогично тому, как общие классы используют <T extends Number> в методе.