универсальный шаблон java - PullRequest
8 голосов
/ 08 июня 2011

У меня есть вопрос об использовании подстановочных знаков в универсальных типах Java: какова основная разница между List<? extends Set> и List<T extends Set>?Когда я буду использовать либо?

Ответы [ 5 ]

8 голосов
/ 08 июня 2011

Две причины:

Чтобы избежать ненужных приведений:

Вы должны использовать вариант T для таких случаев:

public <T extends Set> T firstOf(List<T> l) {
    return l.get(0);
}

С ? это станет:

public Set firstOf2(List<? extends Set> l) {
    return l.get(0);
}

... который не дает такое же количество информации вызывающей стороне метода firstOf. Первая версия позволяет вызывающей стороне сделать это:

SubSet first = firstOf(listOfSubSet);

во второй версии вы вынуждены использовать приведение для компиляции:

SubSet first = (SubSet)firstOf(listOfSubSet);

Для обеспечения соответствия типов аргументов:

public <T extends Set> boolean compareSets(List<T> a, List<T> b) {
    boolean same = true;
    for(T at : a) {
        for (T bt: b) {
             same &= at.equals(bt);
        }
    }
    return same;
}

Не существует прямого эквивалента использования ? вместо T для этого. Обратите внимание, что из-за единой диспетчеризации Java в приведенной выше версии компилятор вызовет метод at equals(T), который может значительно отличаться от метода at * equals(Set) или equals(Object).

1 голос
/ 08 июня 2011

Разница здесь в том, что во второй версии у вас есть переменная типа T, которая ссылается на конкретный подтип Set, который содержит List. Это необходимо в тех случаях, когда необходимо убедиться, что другой тип имеет тот же тип, что и тип, содержащийся в списке. Пара простых примеров:

// want to ensure that the method returns the same type contained in the list
public <T extends Set> T something(List<T> list) {
  ...
}

// want to ensure both lists contain the exact same type
public <T extends Set> List<T> somethingElse(List<T> first, List<T> second) {
  ...
}

Простое правило: Используйте переменную типа T extends Foo в сигнатуре вашего метода, если один и тот же тип необходим в двух местах. Параметры метода находятся в одном месте, а тип возврата метода - в другом месте. Используйте подстановочный знак ? extends Foo, если вам просто нужно убедиться, что вы имеете дело с «чем-то, что является Foo» в одном месте.

В сторону: не используйте необработанный тип Set.

0 голосов
/ 08 июня 2011

Подстановочный тип G<? extends A> - это супертип любого G<Ai>, где Ai - это подтип A

Другими словами, G<? extends A> - это тип объединения G<A0>, ..., G<An>.

0 голосов
/ 08 июня 2011

Мы используем подстановочные знаки, чтобы указать, что элемент типа соответствует чему-либо. ? обозначает неизвестный тип.

List<? extends Set> является примером ограниченного подстановочного знака , и в нем говорится, что список может принимать любой подтип Set (например, HashSet) List<T extends Set>, с другой стороны, позволяет T быть ограниченным типом, расширяющим Set.

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

0 голосов
/ 08 июня 2011

Вы используете List<? extends Set>, когда объявляете переменную.Например:

List<? extends Number> l = new ArrayList<Integer>();

List<T extends Number> может использоваться в объявлении класса или метода.Это позволит вам написать T вместо <? extends Number> позже в функции.

public <T extends Number> int addAll(List<T> list) {
    int result = 0;
    for (T t : list) {
        result += t.intValue();
    }
    return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...