То, почему делают мы имеем, содержит (Возразите o) вместо содержит (E e)?

Это должно поддержать назад совместимость с более старыми (un-genericized) версиями Collection? Или есть ли более тонкая деталь, которую я пропускаю? Я вижу этот шаблон, повторенный в remove также (remove(Object o)), но add genericized как add(E e).

17
задан Vivin Paliath 8 June 2010 в 00:43
поделиться

5 ответов

contains () принимает объект , потому что объект, которому он соответствует, не обязательно должен быть того же типа, что и объект, который вы передаете в , содержит () ; требуется только, чтобы они были равны. Из спецификации contains () , contains (o) возвращает истину, если существует объект e такой, что (o == null? E == null: o.equals (e)) верно.Обратите внимание, что нет ничего, требующего, чтобы o и e были одного типа. Это следует из того факта, что метод equals () принимает в качестве параметра Object , а не только того же типа, что и объект.

Хотя обычно может быть правдой, что для многих классов equals () определено так, что его объекты могут быть равны только объектам его собственного класса, это, конечно, не всегда так. Например, спецификация для List.equals () говорит, что два объекта List равны, если они оба являются List s и имеют одинаковое содержимое, даже если это разные реализации List. Итак, возвращаясь к примеру в этом вопросе, можно иметь Collection , и я могу вызвать contains () с LinkedList как аргумент, и он может вернуть истину, если есть список с таким же содержимым. Это было бы невозможно, если бы contains () был универсальным и ограничивал его тип аргумента до E .

Фактически, тот факт, что contains () принимает любой объект в качестве аргумента, дает интересное использование, когда вы можете использовать его для проверки существования объекта в коллекции, который удовлетворяет определенному свойству. :

Collection<Integer> integers;
boolean oddNumberExists = integers.contains(new Object() {
    public boolean equals(Object e) {
        Integer i = (Integer)e;
        if (i % 2 != 0) return true;
        else return false;
    }
});
11
ответ дан 30 November 2019 в 13:45
поделиться

Ответили здесь.
Почему методы Java Collections remove не являются generic?
Вкратце, они хотели максимизировать обратную совместимость, потому что коллекции были введены задолго до generics.

И добавлю от себя: видео, на которое он ссылается, стоит посмотреть.
http://www.youtube.com/watch?v=wDN_EYUvUq0

update
Чтобы уточнить, человек, который это сказал (в видео), был одним из тех, кто обновил java maps и collections для использования generics. Если он не знает, то кто.

5
ответ дан 30 November 2019 в 13:45
поделиться

Потому что иначе он мог бы сравниваться только с точным совпадением типа параметра, специально подстановочные коллекции перестали бы работать, например.

class Base
{
}

class Derived
  extends Base
{
}

Collection< ? extends Base > c = ...;

Derived d = ...;

Base base_ref = d;

c.contains( d ); // Would have produced compile error

c.contains( base_ref ); // Would have produced compile error

EDIT
Для сомневающихся, которые думают, что это не одна из причин, вот модифицированный список массивов с генерированным методом contains

class MyCollection< E > extends ArrayList< E >
{
    public boolean myContains( E e )
    {
        return false;
    }
}

MyCollecttion< ? extends Base > c2 = ...;

c2.myContains( d ); // does not compile
c2.myContains( base_ref ); // does not compile

По сути contains( Object o ) - это хак, чтобы заставить этот очень распространенный случай использования работать с Java Generics.

0
ответ дан 30 November 2019 в 13:45
поделиться

"содержит ли эта корзина яблок этот апельсин?"

очевидно, что ответ TRUE не может быть дан. но это все еще оставляет слишком много возможностей:

  1. ответ FALSE.
  2. вопрос плохо сформирован, он не должен пройти компиляцию.

collection api выбрал первый вариант. но и второй вариант был бы вполне логичен. такой вопрос в 99.99% случаев - полная чушь, так что даже не задавайте его!

0
ответ дан 30 November 2019 в 13:45
поделиться

Это потому, что функция contains использует функцию equals, а функция equals определена в базовом классе Object с сигнатурой equals(Object o), а не equals(E e) (поскольку не все классы являются общими). Тот же случай с функцией remove - она обходит коллекцию, используя функцию equals, которая принимает аргумент Object.

Однако это не объясняет решение напрямую, поскольку они могли бы по-прежнему использовать тип E и позволить ему автоматически приводиться к типу Object при вызове equals; но я полагаю, что они хотели позволить функции вызываться на других типах Object. Нет ничего плохого в том, чтобы иметь Collection c; и затем вызвать c.contains(somethingOfTypeBar) - это всегда будет возвращать false, и таким образом устраняется необходимость приведения к типу Foo (которое может вызвать исключение) или, для защиты от исключения, вызова typeof. Поэтому вы можете представить, что если вы итерируете что-то со смешанными типами и вызываете contains для каждого из элементов, вы можете просто использовать функцию contains для всех них, а не использовать защитные функции.

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

4
ответ дан 30 November 2019 в 13:45
поделиться
Другие вопросы по тегам:

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