Зачем в возвращаемом значении если оно boolean или void?
Допустим в первом методе совпадает <T> как в принимаемых так и возвращаемых типах, но во второй метод просто ставит в ступор.
В чём смысл?
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
}
Ответы (2 шт):
В такой записи:
public <T> boolean containsAll(Collection<T> c);
<T> - это не часть возвращаемого типа функции, это индикатор того, что метод параметризирован типом. Метод возвращает просто bool, а вот принимает коллекцию объектов любого типа, именно об этом говорит .
Что качается того, почему во втором методе <T extends E>. Рассмотрим пример:
Collection<Number> numbers = new ArrayList<Number>();
Так так Integer наследуется от Number, то вы справедливо можете ожидать, что можно добавлять объекты типа Integer в коллекцию Collection<Number> используя add:
numbers.add(new Integer(1));
И такого же поведения мы ожидаем от addAll, т.е должно быть допустимо сделать:
Collection<Number> numbers = new ArrayList<Number>();
Collection<Integer> integers = new ArrayList<Integer>();
numbers.addAll(integers);
А для этого нельзя чтоб в addAll принимались только Collection<E> (т.е. в случае этого примера только Collection<Number>), нужно допускать любые коллекции с элементами типов унаследованных от E.
Тут важный момент, что хотя Integer является наследником от Number, Collection<Integer> не является наследником от Collection<Number>.
<T> не в возвращаемом значение, а перед ним. Просто такой синтаксис для определения обобщённых методов. И этот тип Т будет зависить от того что передали в метод. И обратите внимание что при объявление типа Collection<E> для параметра типа исполюзуется E.
В containsAll параметры E и T никак не связаны наследованием поэтому при вызове этого метода, например, на объекти типа Collection можно будет передать Collection. На любом объекте можно вызвать equals, так что такой вариант поведения подходит.
Метод addAll уже ограничивает типы аргументов, которые мы можем в него передать, т.к нам нужно, чтобы коллекция смогла поместить в себя объекты из переданной коллекции. При вызове этого метода на Collection<Number> подойдут аргументы Collection<Number>, Collection<Integer> или Collection<Double>. В этом случаи E будет Number, а T - Number, Integer или Double, и все типы этих объектов можно будет поместить в коллекцию Collection<Number>.
public class SO1418546 {
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> void addAll(Collection<T> c);
}
static class TheCollection<E> implements Collection<E> {
@Override
public <T> boolean containsAll(Collection<T> c) {
return false;
}
@Override
public <T extends E> void addAll(Collection<T> c) {
}
}
public static void main(String[] args) {
Collection<Number> numberCollection = new TheCollection<>();
//OK
numberCollection.containsAll(new TheCollection<String>());
numberCollection.containsAll(new TheCollection<Thread>());
//compile error
numberCollection.addAll(new TheCollection<String>());
//OK
numberCollection.addAll(new TheCollection<Integer>());
numberCollection.addAll(new TheCollection<Number>());
numberCollection.addAll(new TheCollection<Double>());
}
}