2015-03-30 4 views
1

Рассмотрим следующие 2 альтернативных API:Java Дженерики - Список <?> против Список <T>

void method(List<?> list) 
<T> void method(List<T> list) 

Я знаю, что их внутренняя реализация будет иметь много различий, чтобы иметь дело с, такие как List<?> обыкновение иметь возможность писать в список и т. д.

Также, по моему знанию, List<?> разрешит любой параметризованный тип с List в качестве базового типа. Так будет и с List<T>.

Может кто-нибудь сказать мне, есть ли какая-либо разница в том, какие типы входов эти 2 API будут принимать. (НЕ различия в внутренней реализации 2 API).

+0

Я считаю, что они будут принимать точно такой же вход.Ограничения '' появляются только при попытке работать со списком, и тип по какой-то причине имеет значение. – blalasaadri

+0

Я думаю, что 'List ' только добавляет информацию о том, что ни один элемент не будет добавлен в список (за исключением 'null') – jamp

ответ

3

внутренний реализация в точности такая же. Фактически, оба метода, скомпилированные с javac, будут давать одинаковый байтовый код метода, если они вообще компилируются).

Однако, во время компиляции, то первый метод указан в не заботиться о типе компонента из списка, в то время как второй требует, чтобы тип компонента будет инвариантно. Это означает, что всякий раз, когда я вызываю такой метод, тип компонента list будет фиксирован любым использованием сайта вызова.

Я могу назвать свой метод с List<String> и T будет синонимом String во время вызова (с точки зрения компилятора). Я также могу назвать это List<Runnable>, а T будет синонимом Runnable во время разговора.

Обратите внимание, что ваш метод ничего не возвращает, но он очень хорошо мог это сделать в зависимости от аргументов. Рассмотрим метод:

<T> T findFirst(Collection<T> ts, Predicate<T> p) { … } 

Вы можете использовать этот метод для каждого T. BUT Он работает только в том случае, если наш T равен для коллекции и предиката - это то, что означает «инвариантность». Вы можете фактически указать метод применим в более контекстах:

<T> T findFirst(Collection<? extends T> ts, Predicate<? super T> p) { … } 

Этот метод будет работать так же, как и выше, но это было бы более снисходителен, какие типы она принимает. Рассмотрим иерархию типов A extends B extends C. Тогда можно было бы назвать:

Collection<A> cs = …; 
Predicate<C> p = …; 
B b = findFirst(cs, p); 

Мы называем тип tsковарианта и тип p (в подписи метода) контравариантного.

Подстановочные знаки (?) - это другое дело. Они могут быть ограничены (как и в наших случаях выше) как ко- или контравариантные. Если они не ограничены, компилятор действительно нуждается в конкретном типе для заполнения во время компиляции (поэтому вы иногда получаете такие ошибки, как «тип wildcard-# 15 не соответствует шаблону -17»). Конкретные правила изложены в Java Language Specification, Section 4.5.1.

+1

Не могли бы вы подробнее рассказать о своем втором абзаце? –

+0

Я просто расширил свой ответ. – llogiq

+0

Спасибо, но вы еще не говорите о List . В моем понимании все, что вы рассказали о списке выше, по-прежнему будет применимо к списку с точки зрения вызывающего абонента. Я искал различия, которые видел вызывающий. –

Смежные вопросы