Вопрос по java, collections, unbounded-wildcard, generics, types – В чем разница между Collection <?> И Collection <T>

23

Я в основном разработчик C #, и я преподавал структуры данных моему другу, и они используют Java в своем университете, и я видел такое выражение в Java:

void printCollection(Collection<?> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

Я не видел такого в C #, поэтому мне интересно, в чем разница междуCollection<T> а такжеCollection<?> в Java?

void printCollection(Collection<T> c) {
    for (Object e : c) {
        System.out.println(e);
    }
}

Я думаю, что это тоже могло быть написано выше. Парень в документации сравнивалCollection<Object> а такжеCollection<T> хоть.

Примеры взяты изhttp://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

Ты имеешь ввидуvoid printCollection(Collection<T> c) или же<T> void printCollection(Collection<T> c)? Последний является универсальным методом. Первый не является универсальным методом и должен быть объявлен в универсальном классе с параметром типаT newacct

Ваш Ответ

4   ответа
26

Collection<?> коллекция параметров неизвестного типа

Что касается звонящего, то нет разницы между

void printCollection(Collection<?> c) { ... }

а также

<T> void printCollection(Collection<T> c) { ... }

Однако последнее позволяет реализации ссылаться на параметр типа коллекции и поэтому часто является предпочтительным.

Прежний синтаксис существует, потому что не всегда возможно ввести параметр типа в правильной области видимости. Например, рассмотрим:

List<Set<?>> sets = new ArrayList<>();
sets.add(new HashSet<String>());
sets.add(new HashSet<Integer>());

Если бы я должен был заменить? по некоторому параметру типаTвсе наборы вsets будет ограничен одним и тем же типом компонента, то есть я больше не могу помещать наборы с разными типами элементов в один и тот же список, о чем свидетельствует следующая попытка:

class C<T extends String> {
    List<Set<T>> sets = new ArrayList<>();

    public C() {
        sets.add(new HashSet<String>()); // does not compile
        sets.add(new HashSet<Integer>()); // does not compile
    }
}
Я не уверен, что понял ваш последний пример. Не могли бы вы сформулировать это немного больше / Tarik
@meriton: прямо сейчас имеет смысл. Благодарю. Tarik
Готово. Это теперь понятнее?
5

Collection<T> ты мог бы сделать

void printCollection(Collection<T> c) {
    for (T e : c) {
        System.out.println(e);
    }
}

Collection<?> Вы только знаете, что коллекция содержит объекты.

так? сCollection<?> ты мог бы сделатьvoid printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e); } }
Тогда почему бы и нетObject так как нам нужно использоватьObject позже в реализации метода? Tarik
5

который использует неограниченный подстановочный знак (?) На самом деле означает? extends Object (все, что расширяет объект).

Это, в Java, подразумевает природу только для чтения, а именно, нам разрешено читать элементы из общей структуры, но нам не разрешено вставлять что-либо обратно в нее, потому что мы не можем быть уверены в фактическом типе элементов в Это.

Поэтому, я полагаю, это очень правильный подход вprintCollection Обсуждаемый метод, по крайней мере, пока мы не встретим ситуацию, в которой нам нужно принять тип.

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

Например, если нужно синхронизировать коллекцию, я мог бы просто сделать:

<T> void printCollection(Collection<T> c) {
    List<T> copy = new ArrayList<T>();
    synchronized(c) {
        copy.addAll(c);
    }
    for (T e : copy) {
        System.out.println(e);
    }
}

Я очень легко создал новую коллекцию типаTи скопируйте все элементы оригинальной коллекции во второй. Это я могу сделать, потому что я могу предположить, что тип коллекцииT, и не?.

Я мог бы, конечно, сделать то же самое с первым методом (с использованием неограниченного символа подстановки), но он не настолько чист, я должен был предположить, что типом коллекции является объект, а не? (который нельзя использовать как аргумент типа:new ArrayList<?>()).

void printCollection(Collection<?> c) {
    List<Object> copy = new ArrayList<Object>();
    synchronized(c) {
        copy.addAll(c);
    }
    for (Object e : copy) {
        System.out.println(e);
    }
}
19

Collection<?> (произносится как «коллекция неизвестного») - это коллекция, тип элемента которой соответствует чему угодно, тогда какCollection<T> обозначает коллекцию типаT.

Как обычно Анжелика ЛангерFAQ по дженерикам имеет обширную дискуссию на эту тему, которую необходимо прочитать, чтобы полностью понять все об обобщениях в Java и, в частности, неограниченных подстановочных знаках (предмете этого вопроса). Цитата из FAQ:

The unbounded wildcard looks like " ? " and stands for the family of all types. The unbounded wildcard is used as argument for instantiations of generic types. The unbounded wildcard is useful in situations where no knowledge about the type argument of a parameterized type is needed

Для дальнейших технических деталей, проверьте раздел& # xA7; 4.5.1 Тип аргументов и подстановочные знаки изСпецификация языка Java, в котором говорится, что:

Type arguments may be either reference types or wildcards. Wildcards are useful in situations where only partial knowledge about the type parameter is required.

Интересно, есть ли прирост производительности друг над другом. Tarik
Ничего, из-заtype erasure обе формы полностью эквивалентны во время выполнения.

Похожие вопросы