2009-11-02 9 views
7

Parece que no puedo obtener una instancia de HashSet para que funcione como se esperaba. El código que utiliza es la siguiente:HashSet permite duplicados

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()); 
    } 
    } 
} 

Subclase

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(); 
    } 
} 

Este código salidas

[email protected]:~/Documents$ javac testing/Subclass.java 
[email protected]:~/Documents$ javac tester.java 
[email protected]:~/Documents$ java tester 
Set size 2 
Set size 3 
sub acctNbr 007812 
sub acctNbr 007812 
sub acctNbr 007813 
[email protected]:~/Documents$ 
+2

¿Qué comportamiento espera y cómo es diferente del comportamiento que está viendo? –

Respuesta

20

Necesita anular 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 equals(Object) definido en Object para pruebas de igualdad.

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

+4

No olvide sobrescribir hashCode() también. –

+0

El OP ya ha reemplazado hashCode() correctamente, pero este sigue siendo un punto importante. – Adamski

5

No anuló 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 pretende hacer.

+0

Boo a solo una etiqueta de anulación opcional. –

+2

No necesita verificar nulo, ya que 'instanceof' devuelve falso para una referencia nula. –

+0

De acuerdo, una comprobación estricta de @Override habría señalado el problema de inmediato. – andersoj

0

En primer lugar, parece que su equals(Subclass other) debe ser equals(Object other) para anular el método java.lang.Object.equals(), como desee. Probablemente el conjunto llame a la implementación subyacente equals().

+0

Sí, o más precisamente, exactamente lo que dijo Bombe. – andersoj

0

Su método igual nunca se llama. La firma de equals requiere que tome un Object, no en alguna otra clase (incluyendo cualquier clase que esté implementando equals).

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

Dos meta-puntos:

En primer lugar, se interpongan en el hábito de usar @Override cada vez que se cree que está sustituyendo un método. Eso habría causado que su código de ejemplo no compilara, lo que lo llevaría a descubrir el problema.

En segundo lugar, si está utilizando un IDE, y no resaltó una buena advertencia en negrita para usted, está mal configurado. ¡Deberías arreglarlo!

Y si no está usando un IDE, realmente debería serlo. Tan pronto como haya escrito public boolean equals(Subclass other), el texto cambiará de color y se mostrará una advertencia que le indica cuál es su problema probable.

Por cierto, el lenguaje estándar para equals() que he coincidido en decir esto:

@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 anteponiendo un if (object == this) { return true; } pero realmente no vale la pena hacer un hábito regular de eso.

1

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

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

Cuestiones relacionadas