2009-11-02 3 views
7

Я не могу получить экземпляр HashSet для работы, как ожидалось. Код, который я использовал это следующим образом: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(); 
    } 
} 

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

[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

Какое поведение вы ожидаете и чем оно отличается от поведения, которое вы видите? –

ответ

20

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

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

+4

Не забудьте также переопределить hashCode(). –

+0

OP был уже переопределен hashCode() правильно, но это все еще важный момент. – Adamski

5

Вы не правильно переопределили 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) создает второй метод, который является не то, что вы намеревались сделать.

+0

Boo только для необязательного тега переопределения. – 2009-11-02 20:38:51

+2

Вам не нужно проверять значение null, так как 'instanceof' возвращает false для нулевой ссылки. –

+0

Согласованная, строгая проверка @Override сразу указала на проблему. – andersoj

0

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

+0

Да, точнее, именно то, что сказал Бомбе. – andersoj

0

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

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

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

Во-первых, получить в привычку использовать @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

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

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