Подтвердить что ты не робот

В чем разница между A <T extends B> и A <? расширяет B>?

Я новый ученик java. Недавно я читал Generic-программирование и сам смутился с этим...

A<T extends B> and A<? extends B>
4b9b3361

Ответ 1

Прежде всего, это совершенно разные конструкции, используемые в разных контекстах.

A<T extends B> является частью объявления типового типа, такого как

public class A<T extends B> { ... }

Он объявляет общий тип A с параметром типа T и вводит оценку на T, так что T должен быть подтипом B.


A<? extends B> является параметризованным типом с подстановочным знаком, его можно использовать в объявлениях переменных и методов и т.д. как обычный тип:

A<? extends B> a = ...;

public void foo(A<? extends B> a) { ... }

Объявление переменной, например A<? extends B> a, означает, что тип A есть A, параметризованный некоторым подтипом B.

Например, учитывая это объявление

List<? extends Number> l;

вы можете:

  • Назначьте List некоторого подтипа от Number до l:

    l = new ArrayList<Integer>(); 
    
  • Получить из этого списка объект типа Number:

    Number n = l.get(0);
    

Однако вы не можете поместить что-либо в список l, так как вы не знаете фактический тип параметра в списке:

Double d = ...;
l.add(d); // Won't compile

Ответ 2

? - это то, что называется wildcard. Это означает все, что расширяет B.

Когда вы пишете List<T extends String>, ваш List может содержать только элементы типа T.

Когда вы пишете List<? extends String>, ваш List может содержать любой элемент, который extends String

Надеюсь, я понятен, так как эти понятия сложны.

Ответ 3

(длинный комментарий, а не ответ)

Совершенно разные вещи. Сходство в синтаксисе - серьезная ошибка, допущенная Java. И эта ошибка приводит к большей ошибке - многие люди пытаются понять подстановочный знак как параметр типа (например, подстановочный знак)

Не было такой вещи, как A<? extends B>, пока Java не придумала ее. До тех пор синтаксис, используемый исследователями, был A<B+>. Java подумала, что это слишком загадочно для наших бедных программистов, поэтому он придумал синтаксис A<? extends B>, который, кажется, лучше читается в первом раунде.

Хорошо, это чертовски многословно и уродливо. Если API имеет несколько подстановочных знаков, это похоже на рвоту символов.

Но хуже то, что это путаница. Он выглядит как параметр типа. И Java сделала это специально! Java не верила, что ее программисты могут когда-либо понимать ковариантные типы, поэтому синтаксически это делало конвариантные типы похожими на параметризованные типы, направляя программистов на ошибочный способ понимания, который, по общему признанию, может быть полезен в случаях, но в конечном итоге делает людей не знающими.

Ответ 4

Дженерики - сложный предмет в целом, и особенно в Java. Но в основном разница заключается в следующем:

T расширяет B

Существует определенный тип T, он ограничен только B или подклассом B, но это определенный тип знания. Любая простая старая общая декларация похожа на высказывание: <T extends Object> Говоря, что T extends B, мы говорим, что T более ограничен, чем любой объект, он должен быть конкретно типом B.

? расширяет B

Это означает, что общий тип неизвестен точно, но то, что мы можем сказать об этом, состоит в том, что оно расширяет B. Это может быть B, это может быть подкласс B. С подстановочным знаком и расширением слова это означает что вы можете получить B из объекта, но вы не можете помещать что-либо в объект безопасным типом. (? super B означает обратное - вы можете поместить что-то в параметр метода, который является B или суперклассом B, но вы не можете быть уверены, каким будет возвращаемое значение метода.)