Лучший способ использовать содержит в ArrayList в Java? - PullRequest
8 голосов
/ 12 июня 2009

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

Теперь я вижу две альтернативы этому, и мне интересно, какой вариант лучше:

  1. Для реализации моего собственного метода содержимого путем перебора ArrayList и проверки равенства каждого элемента с искомым, а затем прерывания цикла.

  2. Или использовать HashMap моего типа в качестве ключа с целым числом в качестве значения вместо ArrayList. Здесь я могу использовать метод containsKey, чтобы проверить, существует ли элемент в HashMap.

Единственное предостережение, касающееся подхода №2, заключается в том, что в моем случае значение в значительной степени избыточно.

Ответы [ 5 ]

23 голосов
/ 12 июня 2009

Скорее всего, вы просто забыли переопределить equals() и hashCode() в вашем типе. equals() - это то, что contains() проверяет.

Из Javadoc :

Возвращает true, если этот список содержит указанный элемент. Более формально, возвращает true тогда и только тогда, когда этот список содержит хотя бы один элемент e такой, что (o==null ? e==null : o.equals(e)).

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

(И если вы не переопределите equals и hashCode, использование ваших типов в качестве ключей в HashMap было бы одинаково бесполезным.)


Редактировать: Обратите внимание, что для переопределения необходимо предоставить точную подпись.

class MyDataType {
    public boolean equals(MyDataType other) { // WRONG!
        ...
    }
    public boolean equals(Object other) { // Right!
        ...
    }
}

Это очень веский аргумент для использования аннотации @Override; первый пример потерпел бы неудачу во время компиляции, если бы был отмечен @Override.

14 голосов
/ 12 июня 2009

Я предполагаю, что вы написали только «строго типизированный» метод equals вместо переопределения equals (Object). Другими словами, если у вас есть:

public boolean equals(Foo f)

вам нужно

public boolean equals(Object o)

, а также переопределить Object.equals.

Это соответствовало бы "равно работает", но не содержит, потому что ваши тесты, вероятно, вызывают строго типизированные равенства, а ArrayList - нет.

3 голосов
/ 12 июня 2009

Вы переопределили метод equals? Это необходимо для правильной работы содержимого.

2 голосов
/ 12 июня 2009

Помните, что если вы не переопределите метод equals (), то два объекта вашего типа будут равны только в том случае, если они являются одинаковым экземпляром этого объекта. Класс ArrayList использует этот метод для проверки того, что он содержит данный объект. Кроме того, вам необходимо точно соответствовать сигнатуре, что означает, что он должен принимать объект в качестве параметра, а не Foo.

Кроме того, контракт Object предусматривает, что вы должны переопределять hashCode () всякий раз, когда переопределяете equals (). Если вы этого не сделаете, то HashMap или HashSet не будут идентифицировать ваши два объекта как равные, даже если это делает ArrayList (HashMap проверяет идентичные хэши, а затем вызывает equals () для их проверки на фактическое равенство). Таким образом, если ArrayList говорит, что два элемента не равны, то HashMap также не сможет. Это означает, что ваше второе решение не работает.

Я рекомендую проверить, действительно ли вы корректно переопределяете equals () и hashCode () и что их подписи совпадают с сигнатурами в классе Object.

0 голосов
/ 12 июня 2009

может быть, вместо этого использовать класс Integer? тогда вы можете сделать сравнение объектов

...