2011-03-31 3 views
6

вот мой код:HashSet содержит метод, странное поведение

public class testGui { 



    public static void main(String[] arg){ 
     class TESTS{ 
      String t; 

      public TESTS(String t){ 
       this.t = t; 
      } 

      @Override 
      public boolean equals(Object x){ 
       System.out.println("My method is called..."); 
       if(x instanceof TESTS){ 
        TESTS zzz = (TESTS) x; 
        return zzz.t.compareTo(t)==0; 
       } 
       else return false; 
      } 
     } 
     HashSet<TESTS> allItems = new HashSet<TESTS>(); 
     allItems.add(new TESTS("a")); 
     allItems.add(new TESTS("a")); 
     System.out.println(allItems.contains(new TESTS("a"))); 
    } 

} 

Я не понимаю, почему HashSet содержит метод не называя мой метод Equals, как упоминалось в их спецификации:

Более формально , добавляет указанный элемент, а, к этому набору, если этот набор не содержит элемент е такой, что (о == NULL е == NULL:? o.equals (е))

Мой код возвращает false и не входит в мой метод equals.

Большое спасибо за ответ!

ответ

13

Когда вы переопределяете equals, вы также должны переопределить hashCode. В противном случае равные объекты будут иметь разные хеш-коды и считаться неравными.

Настоятельно рекомендуется не переуступать только hashCode. Но это не существенно, так как неравные объекты могут иметь один и тот же хэш-код.

+2

Они не будут считаться неравными. Просто HashSet даже не вызывает метод equals, потому что он делает это только для хэш-кодов, ведущих к одному и тому же ведро. И переопределение только hashCode не имеет никакого смысла, так как HashSet всегда будет называть равным для объектов, имеющих одинаковые хэш-коды. –

+0

@ JB, да, тот факт, что они приводят к разным ведрам, означает, что они считаются «неравными» (считаются разными объектами). Я не имею в виду метод «equals», когда я использую этот термин. Я также соглашаюсь, что переопределение только «hashCode» нелогично, поэтому я настоятельно рекомендовал его. Однако он не нарушает контракт. –

+1

Было бы неплохо, если бы в java-документации упоминалось, что hashcode вызывается первым. Я просто сожгла эту проблему в java 5. – Aaron

3

Вы также должны использовать hashCode, чтобы оно соответствовало equals. HashSet использует метод hashCode, чтобы решить, какое ведро положить предмет, и вызывает equals только тогда, когда хеш-код двух элементов одинаковый.

Эффективное Java, второе издание обсуждает это правило (и последствия нарушения его) в Пункт 9: Всегда переопределения hashCode при перекрытии equals.

+0

Спасибо большое, ребята, это было действительно полезно, я нашел ответ, прежде чем вы ответили (не знали, как отменить вопрос), но то, что вы написали, это то, что я сделал, он решил мою проблему;). – Abbadon

7

HashSet зависит от HashCode каждого объекта. Перед вызовом метода equals вызывается метод hashCode. Если хэш-коды равны, то хэшсет считает это достойным оценки метода equals.

Реализовать метод Hashcode, что если a.equals (б) == верно, то a.hashCode() == b.hashCode()

и он должен начать работать, как можно было бы ожидать.

0

Поскольку большинство комментариев было ... просто переопределить метод hashcode (образец ниже), и вы должны быть хорошими.

@Override 
     public int hashCode() { 
      return t.hashCode()*31; 
     } 
+0

Что вы получаете, умножая на 31? –

+0

эта тема поможет http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier – Prasanna

Смежные вопросы