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

Общий сбор

Это часть интерфейса коллекции Java (1.6):

public interface Collection<E> extends java.lang.Iterable<E> { 
    /* ... */   
    boolean containsAll(java.util.Collection<?> objects);    
    boolean addAll(java.util.Collection<? extends E> es);    
    boolean removeAll(java.util.Collection<?> objects);    
    boolean retainAll(java.util.Collection<?> objects);
    /* ... */   
}

Почему addAll имеет <? extends E>, а removeAll имеет <?>

4b9b3361

Ответ 1

Я не знал, что я googled. Я получил это объяснение здесь: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html

Копирование части:

Один элемент обобщенного API коллекций, который вначале часто путается, - это подписи containsAll(), removeAll() и retainAll(). Вы можете ожидать, что подписи для remove() и removeAll() будут:

interface Collection<E> { 
  public boolean remove(E e);  // not really
  public void removeAll(Collection<? extends E> c);  // not really
}

Но это на самом деле:

interface Collection<E> { 
  public boolean remove(Object o);  
  public void removeAll(Collection<?> c);
}

Почему это? Опять же, ответ кроется в обратной совместимости. Контракт интерфейса x.remove(o) означает "если o содержится в x, удалите его, иначе ничего не делайте". Если x - общий набор, o не обязательно должен быть совместим с типом параметра типа x. Если removeAll() был генерализован только для вызываемого, если его аргумент был совместим с типом (Collection<? extends E>), то определенные последовательности кода, которые были законными до дженериков, стали бы незаконными, например:

// a collection of Integers
Collection c = new HashSet();
// a collection of Objects
Collection r = new HashSet();
c.removeAll(r);

Если вышеприведенный фрагмент был генерализован очевидным образом (сделав ca Collection<Integer> и ra Collection<Object>), тогда код выше не будет компилироваться, если подпись removeAll() потребовала, чтобы его аргумент был Collection<? extends E>, вместо того, чтобы быть не-op. Одной из ключевых целей генерации библиотек классов было не разбить или изменить семантику существующего кода, поэтому remove(), removeAll(), retainAll() и containsAll() должны были быть определены с более слабым типом ограничений, чем они возможно, они были переработаны с нуля для дженериков.

Ответ 2

Для любой коллекции, содержащей элементы типа E, addAll должен иметь возможность обрабатывать входные коллекции не только E, но и все ее подклассы. Следовательно, <? extends E>. Без этого вы не могли бы добавить все элементы List<Integer> в List<Number>, что явно не правильно. *

Для удаления ограничения не должны быть строго установлены, и нет никакого вреда в попытке удалить элементы коллекции какого-то совершенно несвязанного типа. Например. вы можете иметь коллекцию Number s, о которой вам известно, что она содержит только Integer s, поэтому передача ее в removeAll на List<Integer> должна работать нормально, и было бы глупо для компилятора чтобы запретить это.

Обратите внимание, что в соответствии с Javadoc, removeAll может опционально генерировать ClassCastException, в зависимости от реализации.

* Причина в том, что в Java дженерики являются инвариантными. Более подробно см., Например, этот поток.

Ответ 3

<?> менее ограничительный, чем <? extends E>.

Нет ничего плохого в удалении апельсина из коллекции яблок; есть много чего не так с добавлением апельсина в коллекцию яблок.

Ответ 4

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

Когда вы удаляете их, удаляются только те из коллекции. Независимо от их типа.

Ответ 5

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

Ответ 6

когда вы добавляете объект, он должен быть подклассом (или под-подклассом и т.д.) основного типа. Когда вы удаляете объект, он возвращает его как тип коллекции. Это хороший пример polymorphism в действии.

Ответ 7

Кто заботится о том, что вы пытаетесь удалить?

Добавление - это что-то еще; мы не хотели бы иметь что-то странное в нашей коллекции.

по запросу; пример:

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Main {

    private static class A {

    }

    public static void main(String[] args) {
        Collection<A> collection_A = new ArrayList<A>();

        Collection<String> collection = new ArrayList<String>();

        // no problem to try and remove things that wouldn't be there in the first place; either way, they are gone afterwards
        collection.removeAll(collection_A);

        // we can't allow this; you would end up with things in your collection that don't belong there
        collection.addAll(collection_A);
    }

}

Ответ 8

Простой пример, иллюстрирующий сказанное:

public class Test {

    public static void main(String[] args) {
        List<String> l = new ArrayList<String>();
        System.out.println(l.remove(new Object())); //false
        System.out.println(l.contains(new Object())); //false
//        l.add(new Object()); // does not compile
    }

}

Ответ 9

Чтобы удалить ограничение, не нужно, поэтому только <?>, но при добавлении мы должны проверить и затем добавить для безопасности типа, поэтому addAll имеет ограничение <? extends E>

Ответ 10

С помощью addAll вы хотите добавить все элементы, являющиеся подтипом родового типа. Сюда входит добавление всех элементов List<String> к List<Object>. Мы используем ? extends E для принятия любой коллекции, содержащей тип, хранящийся в этой коллекции или любой подтип.

boolean addAll(java.util.Collection<? extends E> es);
List<Number> numbers = ...;
List<Integer> integers = ...;
numbers.addAll(integers);//works    

boolean addAll(java.util.Collection<E> es);
numbers.addAll(integers);//does not work E != Integer

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

boolean addAll(java.util.Collection<? extends E> es);
List<Number> numbers = ...;
List<Integer> integers = ...;
List<String> strings = ...;
numbers.addAll(integers);//works
numbers.addAll(strings);//error

boolean addAll(java.util.Collection<?> es);
numbers.addAll(strings);//works - now we have strings in our Number collection

Мы можем использовать ? для удаления объектов, поскольку попытка удалить строку из списка номеров не влияет на List<Number>.

boolean removeAll(java.util.Collection<?> objects);
List<Objects> objects = ...;
List<Integer> integers = ...;
List<Number> numbers = ...;
numbers.removeAll(objects);//works 
numbers.removeAll(integers);//works

boolean removeAll(java.util.Collection<? extends E> objects);
numbers.removeAll(objects);//does not work 
numbers.removeAll(integers);//works

boolean removeAll(java.util.Collection<? super E> objects);
numbers.removeAll(objects);//works 
numbers.removeAll(integers);//does not work