HashSet permite duplicados

Parece que no puedo hacer que una instancia de HashSet funcione como esperaba. El código que utilicé es el siguiente:

 import testing.Subclass; import java.util.HashSet; public class tester { public static void main(String[] args) throws Exception { HashSet set = new HashSet(); 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()); } } } 

Subclase

 public class Subclass implements Comparable { 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(); } } 

Este código produce

 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$ 

Es necesario anular los equals(Object) . En lugar de hacer esto, ha implementado un método equals con la firma equals(Subclass) . En consecuencia, su HashSet está utilizando el método predeterminado de equals(Object) definido en Object para pruebas de igualdad.

La implementación por defecto de equals(Object) se basa en la identidad del objeto y, por lo tanto, el conjunto “le permite” agregar dos String s que, aunque son semánticamente iguales, no son el mismo objeto.

No Object.equals() correctamente Object.equals() .

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

El método boolean equals(Subclass other) crea un segundo método que no es lo que pretendía hacer.

Dos meta-puntos:

Primero, @Override el hábito de usar @Override cada vez que crea que está anulando un método. Eso habría provocado que su código de ejemplo no se comstackra, lo que lo llevaría a descubrir el problema.

Segundo, si está usando un IDE, y no resaltó una advertencia audaz, ¡está mal configurado! Deberías arreglarlo!

Y si no estás usando un IDE, realmente deberías serlo. Tan pronto como escribiste public boolean equals(Subclass other) , el texto cambiará de color y aparecerá una advertencia que te indicará cuál es tu problema probable.

Por cierto, el idioma estándar para equals() que he convergido es este:

 @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; } 

En algunos casos, vale la pena anteponer un if (object == this) { return true; } if (object == this) { return true; } pero realmente no vale la pena hacer un hábito regular de eso.

Tuve casi el mismo problema, ya que todos dijeron que es necesario anular el método correcto public boolean equals(Object o) . ¡Pero eso no es suficiente!

También es necesario anular public int hashCode() (como hiciste), de lo contrario, java no llamaría al método equals en absoluto.

En primer lugar, parece que tus equals(Subclass other) deberían ser equals(Object other) para anular el método java.lang.Object.equals() , como quieras. Probablemente el conjunto está llamando a la implementación de equals() subyacente.

Tu método de iguales nunca se llama. La firma de equals requiere que tome un Object , no otra clase (incluida la clase que sea que esté implementando equals ).

 public boolean equals(Object other) { ... }