Есть разница между каждым из них, и я собираюсь объяснить большинство из них. Давайте начнем с нашего примера. Я использую эту иерархию классов:
class Food {}
class Apple extends Food {}
class Orange extends Food {}
class RedApple extends Apple {}
List<Food> listFood = new ArrayList<>();
List<Apple> listApple = new ArrayList<>();
List<Orange> listOrange = new ArrayList<>();
List<RedApple> listRedApple = new ArrayList<>();
Теперь начните с первого:
A. public static <T> List<T> backwards(List<T> input)
Этот метод принимает только List<T>
и возвращает List<T>
, и вы не можете отправить listApple
и вернуть listRedApple
. (однако ваш список возврата может содержать RedApple
, поскольку он расширяется Apple
, но тип списка должен быть List<Apple>
и ничего более)
B. public static <T> List<T> backwards(List<? extends T> input)
Вы можете отправить listRedApple
и вернуть listApple
, но вы знаете, что listRedApple
- это "расширение Apple" , поэтому в теле метода java распознает T как Apple. Затем, если вы используете, можете добавлять элементы в listRedApple
, которые отправляются в качестве аргумента, вы можете добавить Apple
в listRedApple
, что не соответствует действительности !!! поэтому компилятор избегает этого и выдает ошибку компиляции. В B вы можете только читать элементы (и получать его как T), но вы не можете ничего добавить к нему.
C. public static <T> List<T> backwards(List<? super T> input)
Вы можете отправить listApple
, а затем в тело метода вы можете добавить что-нибудь, что расширяет Apple
, потому что компилятор видит T как Apple
, а в списке все, что супер из T , вы можете добавить что-нибудь расширяет Apple
.
Однако на этот раз вы ничего не можете прочитать, потому что вы не знаете его тип, за исключением того, что вы получаете его как Object
. (Это список "? Super T" )
Как вы видите здесь, есть разница между ? супер и ? продлить . один из них дает вам доступ для записи, а другой - для чтения. Это реальное использование подстановочных знаков.
D. public static <T> List<? extends T> backwards(List<T> input)
E. public static <T> List<? super T> backwards(List<T> input)
Если вы отправите listApple
, тогда вы вернете List<? extends Apple>
, но вы можете присвоить его любому из listFood
или listApple
или listRedApple
, потому что List<? extends Apple>
может содержать Apple
или RedApple
или что-то еще и мы не можем присвоить его любому List<T>
, потому что тогда мы можем добавить T
к этому списку и, возможно, T
и ? extends T
не совпадают. это одинаково для D
и E
. Вы можете присвоить его List<? extends Apple>
для 'E и List<? super Apple>
для D
и отправить их методу, который нуждается в них в качестве параметра.
F. public static <? extends T> List<T> backwards(List<T> input)
G. public static <? super T> List<T> backwards(List<T> input)
Дайте ошибки компиляции, потому что подстановочный знак не может использоваться как это.
Надеюсь, это поможет вам.
Если что-то не так, любой комментарий приветствуется.