функция не принимает объекты супер типов T? - PullRequest
1 голос
/ 22 января 2020

Я имею дело со следующей загадкой.

class Product {}

static class Fruit extends Product implements Comparable<Fruit> {}

class Apple extends Fruit {}

Function<? super Fruit, ? extends Comparable> fx = Fruit::getCost;
Fruit fruit = new Fruit(1);
Product product = new Product();
fx.apply(product); <-- compile error?

В чем может быть причина того, что FX не принимает объект Product в качестве аргумента? Продукт является родителем фрукта, т.е. удовлетворяет определению «супер фрукт».

Function<? extends Fruit, ? extends Comparable> fx = Fruit::getCost;
Fruit fruit = new Fruit(1);
Apple apple = new Apple(2);
fx.apply(apple); <-- compile error?

Почему яблоко не будет принято в качестве аргумента, если его тип является подтипом фрукта? Яблоко должно удовлетворить "? Удлиняет фрукты".

Ответы [ 4 ]

1 голос
/ 22 января 2020

Подпись типа fx равна <? super Fruit>-><? extends Comparable<?>>. При вызове метода назначение аргументов параметрам похоже на присвоение значений переменным. Вы можете присвоить значение переменной, только если тип значения такой же или подтип, как у переменной. Является ли Product подтипом <? super Fruit>?

Нет.

1 голос
/ 22 января 2020

Я написал что-то, и это помогло мне понять проблему:

    Function<Fruit, ? extends Comparable> fx1 = Fruit::getCost;
    Function<? super Fruit, ? extends Comparable> fx2 = fx1;
    fx2.apply(new Product()); <-- COMPILER ERROR

Функция fx2, которая является fx1, знает / ожидает Фрукт. Если компилятор разрешит Product, это будет проблемой.

    Function<Apple, ? extends Comparable> fx1 = Fruit::getCost;
    Function<? extends Fruit, ? extends Comparable> fx2 = fx1;
    fx2.apply(new Fruit(1));    <-- COMPILER ERROR

Функция fx2, то есть fx1, знает / ожидает Apple. Если компилятор разрешит Fruit, это будет проблемой.

1 голос
/ 22 января 2020

Возможно, это прояснит ситуацию:

Function<Fruit, Integer> costFunc = Fruit::getCost;
Function<? super Fruit, ? extends Comparable<?>> fx = costFunc;

Каждый объект с типизированной c типизацией имеет точные аргументы типа. Хотя вы можете сослаться на Функция как Function<? super Fruit, …>, не существует такого объекта как объект. Есть функция , функция и функция , но ни один существующий объект не может иметь подстановочный тип (то есть тип, который использует знак вопроса). ? - это только способ сообщить компилятору, что вы не уверены , каков фактический тип generi c объекта.

В приведенном выше коде компилятор видит, что fx объявлен как Function<? super Fruit, ? extends Comparable<?>>. Компилятор не знает, каков фактический тип generi c входного параметра функции, потому что вы сказали ему, что это некоторый специфицированный c тип , который может быть Fruit, или любой класс или интерфейс наследуется Fruit.

Таким образом, компилятор не знает, безопасно ли передавать Product в метод apply. Что если fx содержит в качестве первого аргумента функцию, для которой требуется фрукт, а не какой-либо продукт? То есть Function<Fruit, …> (что показывает пример)?

Если вы хотите объявить функцию, которая принимает Fruit или любой супертип Fruit, вы бы написали Function<Object, …> без использования подстановочных знаков вообще.

1 голос
/ 22 января 2020

Давайте подумаем логически о том, что может быть Function<? super Fruit, ? extends Comparable> (для четырех примеров):

  1. Это может быть функция, которая отображает Fruit объекты на что-то сопоставимое.
  2. Это может быть функция, которая отображает Product объекты на что-то сопоставимое.
  3. Это может быть функция, которая отображает Comparable<Fruit> на что-то сопоставимое.
  4. Это может быть функция, которая отображает Object объекты с чем-то сопоставимыми.

В случаях 2. и 4. объект Product удовлетворяет требованиям быть параметром функции, но в случаях 1. и 3. - где функция принимает только Fruit или Comparable<Fruit> - Product не является допустимым аргументом для функции. Таким образом, функция может не вызываться с вашим аргументом типа Product.


Давайте подумаем о том, чем может быть Function<? extends Fruit, ? extends Comparable> (для четырех примеров):

  1. Это может быть функция, которая отображает Fruit объекты на что-то сопоставимое.
  2. Это может быть функция, которая отображает Apple объекты на что-то сопоставимое.
  3. Это может быть функция, которая отображает Banana объектов с чем-то сопоставимым.
  4. Это может быть функция, которая отображает некоторый подкласс Apple на что-то сопоставимое.

В случаях 1. и 2., Apple объект удовлетворяет требованиям быть параметром функции, но в случаях 3. и 4. - когда функция принимает только Banana или некоторый подкласс Apple - Apple не является допустимым аргументом для функции , Таким образом, функция может не вызываться с вашим аргументом типа Apple.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...