Согласованные результаты Equals (), но несовместимые результаты TreeMap.containsKey () - PullRequest
2 голосов
/ 23 апреля 2010

У меня есть следующий объект Node:

    private class Node implements Comparable<Node>(){
         private String guid();

         ...

         public boolean equals(Node o){
             return (this == o);
         }

         public int hashCode(){
              return guid.hashCode();
         }

         public int compareTo(Node o){
            return (this.hashCode() - o.hashCode());
         }

         ...

    }

И я использую его в следующем TreeMap:

TreeMap<Node, TreeSet<Edge>> nodes = new TreeMap<Node, TreeSet<Edge>>();

Теперь древовидная карта используется в классе Graph для хранения узлов, находящихся в данный момент в графе, вместе с набором их ребер (из класса Edge). Моя проблема, когда я пытаюсь выполнить:

   public containsNode(n){
        for (Node x : nodes.keySet()) {
            System.out.println("HASH CODE: ");
            System.out.print(x.hashCode() == n.hashCode());
            System.out.println("EQUALS: ");
            System.out.print(x.equals(n));
            System.out.println("CONTAINS: ");
            System.out.print(nodes.containsKey(n));
            System.out.println("N: " + n);
            System.out.println("X: " + x);
            System.out.println("COMPARES: ");
            System.out.println(n.compareTo(x));
            }
        }

Иногда я получаю следующее:

HASHCODE: верно РАВНЫ: верно СОДЕРЖИТ: false N: foo X: foo СРАВНЕНИЯ: 0

Кто-нибудь имеет представление о том, что я делаю неправильно? Я все еще новичок во всем этом, поэтому я заранее извиняюсь, если пропускаю что-то простое (я знаю, hashCode() на самом деле не имеет значения для TreeMap, но я решил, что включу это).

edit1: добавлено compareTo() информация о методе.

Ответы [ 3 ]

5 голосов
/ 23 апреля 2010

TreeSet не использует equals () для определения равенства. Вместо этого он использует Comparator (или Comparable). Чтобы заставить его работать правильно, вы должны соблюдать последовательность с правилом равных :

"Порядок, наложенный компаратором c на множестве элементов S называется в соответствии с равными, если и только если c.compare (e1, e2) == 0 имеет то же самое логическое значение как e1.equals (e2) для каждый е1 и е2 в S ".

Полагаю, вы не следуете этому правилу (вы не предоставили реализацию метода CompareTo). Если правило не соблюдается, у набора деревьев не будет нормального поведения набора.

Подробнее см. http://eyalsch.wordpress.com/2009/11/23/comparators/.

- EDIT -

Теперь, когда вы предоставили свою реализацию CompareTo, ясно, что она имеет недостаток. Может возвращать 0 для 2 узлов, которые не равны (и имеют одинаковый хэш-код). В результате этого вы не можете добавить 2 элемента с одинаковым хеш-кодом в ваш TreeSet!

5 голосов
/ 23 апреля 2010

Здесь есть пара неправильных вещей.

  • Вы не переопределили Object.equals. Используйте @Override public boolean equals(Object obj).
  • В compareTo имеется потенциальная ошибка переполнения целых чисел. Это, вероятно, причина этой конкретной ошибки. Это нарушит сортировку, и, следовательно, поиск может быть неудачным.
  • Метод compareTo утверждает, что два экземпляра равны, если хеш-код совпадает (может быть трудно перехватить ошибку, без проверки кода).

По поводу целочисленного переполнения см. Вопрос Почему сломан мой простой компаратор?

0 голосов
/ 23 апреля 2010

Проверьте свой компаратор.

containsKey() вызывает getEntry(), который может полагаться на компаратор.Если он сломан, вы можете ожидать противоречивые результаты.

...