Почему у нас есть (Объект o) вместо содержит (E e)? - PullRequest
17 голосов
/ 08 июня 2010

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

Ответы [ 5 ]

11 голосов
/ 08 июня 2010

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

Хотя обычно может быть верно, что многие классы имеют equals(), определенные так, что его объекты могут быть равны только объектам своего собственного класса, что, конечно, не всегда так. Например, спецификация для List.equals() гласит, что два объекта List равны, если они оба List s и имеют одинаковое содержимое, даже если они являются разными реализациями List. Итак, возвращаясь к примеру в этом вопросе, можно иметь Collection<ArrayList> и для меня вызвать contains() с LinkedList в качестве аргумента, и он может вернуть true, если существует список с таким же содержимым. Это было бы невозможно, если бы 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;
    }
});
5 голосов
/ 08 июня 2010

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

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

update
Чтобы уточнить, человек, который сказал это (вvideo) был одним из людей, которые обновили java-карты и коллекции, чтобы использовать дженерики.Если он не знает, то кто.

4 голосов
/ 08 июня 2010

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

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

На самом деле это напоминает «более новые» свободно типизированные языки, когда смотришь на это так ...

0 голосов
/ 09 июня 2010

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

ясно, что ИСТИННЫЙ ответ не может быть дан. но это все еще оставляет слишком много возможностей:

  1. ответ - ЛОЖЬ.
  2. вопрос не правильно сформирован, он не должен пройти компиляцию.

коллекция API выбрала 1-й. но второй выбор также имеет смысл. такой вопрос - чушь собеседника в 99,99% случаев, так что даже не задавайте!

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

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

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
Для сомневающихся, которые думают, что это не является одной из причин, вот модифицированный список массивов, который будет обобщен, содержит метод

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...