2009-11-02 19 views
7

Non riesco a ottenere un'istanza HashSet per funzionare come previsto. Il codice che ho usato è il seguente:HashSet consente di duplicare

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

sottoclasse

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

Questo codice uscite

[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

Quale comportamento ti aspetti e in che modo è diverso dal comportamento che stai vedendo? –

risposta

20

È necessario eseguire l'override equals(Object). Invece di farlo, hai implementato un metodo equals con la firma equals(Subclass). Di conseguenza, il tuo HashSet utilizza il metodo predefinito equals(Object) definito su Object per il test di uguaglianza.

L'implementazione di default equals(Object) si basa sull'identità dell'oggetto e quindi l'insieme "consente" di aggiungere due String s che, pur essendo semanticamente uguali, non sono lo stesso oggetto.

+4

Non dimenticare di sovrascrivere hashCode(). –

+0

L'OP aveva già sovrascritto hashCode() correttamente, ma questo è ancora un punto importante. – Adamski

5

Non è stato eseguito l'override corretto Object.equals().

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

Il metodo boolean equals(Subclass other) crea un secondo metodo, che non è quello che intendeva fare.

+0

Boo su solo un tag di override facoltativo. –

+2

Non è necessario controllare null, poiché 'instanceof' restituisce false per un riferimento null. –

+0

Accertato, il controllo rigoroso di @Override avrebbe indicato immediatamente il problema. – andersoj

0

Prima ipotesi, sembra che il tuo equals(Subclass other) debba essere equals(Object other) per sostituire il metodo java.lang.Object.equals(), come desideri. Probabilmente il set sta chiamando l'implementazione sottostante equals().

+0

Sì, o più precisamente, esattamente quello che ha detto Bombe. – andersoj

0

Il tuo metodo di uguale non viene mai chiamato. La firma di equals richiede che ci sia un Object, non qualche altra classe (inclusa qualsiasi classe stia applicando equals).

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

Due meta-punti:

In primo luogo, prendere l'abitudine di usare @Override ogni volta che credi di sostituire un metodo. Ciò avrebbe causato la mancata compilazione del codice di esempio, che ha portato alla scoperta del problema.

In secondo luogo, se si sta utilizzando un IDE, e non ha fatto evidenziare un bel avvertimento grassetto per voi, è configurato in modo errato! Dovresti aggiustarlo!

E se non si sta usando un IDE - davvero, in realtà dovrebbe essere. Non appena hai digitato public boolean equals(Subclass other), il testo cambierà colore e verrà visualizzato un avviso che ti dice qual è il tuo probabile problema.

Per inciso, il linguaggio standard per equals() che ho convergenti su è questo:

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

In alcuni casi, vale la pena anteponendo un if (object == this) { return true; } ma è davvero non vale la pena di fare una regolare abitudine di esso.

1

avevo quasi lo stesso problema, come tutti ha detto è necessario eseguire l'override del metodo giusto public boolean equals(Object o). Ma non è abbastanza!

È inoltre necessario eseguire l'override public int hashCode() (come avete fatto), in caso contrario, Java non sarebbe chiamare il metodo equals a tutti.