Почему Java TreeSet‹E› remove(Object) не принимает E

Из Java 6 TreeSet<E> Документация:

boolean remove(Object o):
    Removes the specified element from this set if it is present.

Почему это принимает объект вместо универсального типа E? Единственные объекты, которые могут быть добавлены, относятся к типу E, поэтому следует, что единственный удаляемый тип должен быть типа E.


person ComputerDruid    schedule 04.11.2011    source источник
comment
связанные: stackoverflow.com/questions/857420/   -  person Paul Bellora    schedule 05.11.2011
comment
возможный дубликат Почему методы удаления коллекций Java не являются универсальными?   -  person PhoneixS    schedule 07.08.2013


Ответы (4)


remove(), как и get(), должен работать, когда задан равный элемент (с точки зрения .equals()). В Java возможно (а в некоторых случаях и необходимо) совпадение объектов разных классов. Следовательно, вы не должны ограничивать тип.

person newacct    schedule 05.11.2011

Взяв ответ из первого опубликованного комментария:

Миф:

Популярный миф состоит в том, что это глупо и зло, но это было необходимо из-за обратной совместимости. Но аргумент совместимости не имеет значения; API правильный, независимо от того, считаете ли вы совместимость или нет.

Настоящая причина:

Точно так же методы Java Collections Framework (а также Google Collections Library) никогда не ограничивают типы своих параметров, за исключением случаев, когда это необходимо для предотвращения разрушения коллекции.

Подробнее читайте здесь: Почему Set.contains() принимает объект , а не E?

person zengr    schedule 04.11.2011

Ну, каждый E также является Объектом, и, возможно, у вас есть E не как E в данный момент (например, из источника Event), что делает его удобным для вас. В противном случае вам просто нужно привести его к E только для того, чтобы удалить его.

С точки зрения равенства это не имеет значения: адрес ссылки данного объекта проверяется, если он равен содержимому набора, поэтому не имеет значения, к какому классу он принадлежит.

person Alex Schenkel    schedule 04.11.2011

Это действительно проблема. Если кто-то вызывает remove(o), а тип o не E, обычно это программная ошибка, которая пытается удалить не то, что нужно. Проверка типов не смогла защитить нас от ошибки.

Хотя хорошая IDE (IntelliJ) может обнаруживать такие проблемы и предупреждать нас, разработчики API должны были предоставить более точную сигнатуру, чтобы использовать проверку типов компилятора. (Здесь IDE обманывает - она ​​знает значение Set.remove(), потому что это стандартный API. IDE не будет предоставлять такую ​​​​же помощь для пользовательских API)

Для API запросов, такого как contains(), можно принять аргумент, отличный от E, и вернуть тривиальное значение false. Таким образом, мы можем иметь оба

boolean contains(Object o);
boolean contains2(E o);

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

boolean remove(Object o);
boolean remove2(E o);

В большинстве случаев программисты могут вызывать contains2/remove2 для дополнительной безопасности типов.

person irreputable    schedule 05.11.2011
comment
Вы говорите, что remove2/contains2 это методы TreeSet? Я не вижу этого в API... - person ComputerDruid; 05.11.2011