HashSet позволяет дублировать - PullRequest
7 голосов
/ 02 ноября 2009

Я не могу заставить HashSet экземпляр работать так, как ожидалось. Код, который я использовал, выглядит следующим образом:

import testing.Subclass;
import java.util.HashSet;

public class tester {
  public static void main(String[] args) throws Exception {
    HashSet<Subclass> set = new HashSet<Subclass>();
    set.add(new Subclass("007812"));
    set.add(new Subclass("007813"));
    System.out.println("Set size " + set.size());
    set.add(new Subclass("007812"));
    System.out.println("Set size " + set.size());

    for(Subclass sub : set) {
      System.out.println(" sub acctNbr " + sub.getAcctNbr());
    }
  }
}

Подкласс

public class Subclass implements Comparable<Subclass> {

  public Subclass(String acctNbr) {
    this.acctNbr = acctNbr;
  }
  private String acctNbr;
  public String getAcctNbr() {
    return this.acctNbr;
  }
  public int compareTo(Subclass other) {
    return this.getAcctNbr().compareTo(other.getAcctNbr());
  }

  public boolean equals(Subclass other) {
    if(other.getAcctNbr().equals(this.getAcctNbr()))
      return true;
    else
      return false;
  }
  public int hashCode() {
    return acctNbr.hashCode();
  }
}

Этот код выводит

sross@sross-workstation:~/Documents$ javac testing/Subclass.java
sross@sross-workstation:~/Documents$ javac tester.java
sross@sross-workstation:~/Documents$ java tester
Set size 2
Set size 3
 sub acctNbr 007812
 sub acctNbr 007812
 sub acctNbr 007813
sross@sross-workstation:~/Documents$

Ответы [ 6 ]

20 голосов
/ 02 ноября 2009

Вам необходимо переопределить equals(Object). Вместо этого вы реализовали метод equals с подписью equals(Subclass). Следовательно, ваш HashSet использует метод equals(Object) по умолчанию, определенный в Object для проверки на равенство.

Реализация equals(Object) по умолчанию основана на идентичности объекта, и, следовательно, набор «позволяет» добавить два String s, которые, хотя и семантически равны, не являются одним и тем же объектом.

5 голосов
/ 02 ноября 2009

Вы неправильно переопределили Object.equals().

@Override
public boolean equals(Object other) {
    if ((other == null) || !(other instanceof Subclass)) {
        return false;
    }
    return ((Sublcass) other).getAcctNbr().equals(this.getAcctNbr());
}

Метод boolean equals(Subclass other) создает второй метод, который не является тем, что вы намеревались сделать.

3 голосов
/ 04 ноября 2009

Две мета-точки:

Во-первых, привыкните использовать @Override каждый раз, когда вы считаете, что переопределяете метод. Это привело бы к тому, что ваш пример кода не скомпилировался, что привело бы к обнаружению проблемы.

Во-вторых, если вы используете IDE, и он не выделил для вас красивое смелое предупреждение, он неправильно настроен! Вы должны это исправить!

И если вы не используете IDE - вам действительно следует это сделать. Как только вы введете public boolean equals(Subclass other), цвет текста изменится, и появится предупреждение, сообщающее о вероятной проблеме.

Кстати, стандартная идиома для equals(), к которой я присоединился, такова:

@Override public boolean equals(Object object) {
  if (object instanceof Subclass) {
    Subclass that = (Subclass) object;
    return this.anInt == that.anInt
        && this.aString.equals(that.aString); // for example
  }
  return false;
}

В некоторых случаях стоит предвосхищать if (object == this) { return true; }, но на самом деле не стоит делать из этого привычную привычку.

1 голос
/ 06 сентября 2012

У меня была почти такая же проблема, поскольку все говорили, что вам нужно переопределить правильный public boolean equals(Object o) метод. Но этого недостаточно!

Также необходимо переопределить public int hashCode() (как вы сделали), иначе java вообще не будет вызывать метод equals.

0 голосов
/ 02 ноября 2009

Ваш метод equals никогда не вызывается. Сигнатура equals требует, чтобы он принимал Object, а не какой-то другой класс (включая любой класс, реализующий equals).

public boolean equals(Object other) {
    ...
}
0 голосов
/ 02 ноября 2009

Первое предположение, похоже, что equals(Subclass other) должно быть equals(Object other), чтобы переопределить метод java.lang.Object.equals(), как вы хотите. Вероятно, набор вызывает базовую реализацию equals().

...