#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
and5f
. Это либо то, либо другое 🙂
Ответ №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> в методе.