пользовательский метод equals () не работает должным образом

1

Я реализовал алгоритм Apriori. он работает очень хорошо, но у меня возникла странная проблема: я определил класс Rule для поддержания сгенерированных правил.

Вот:

public class Rule 
{
    private Set<Integer> left;
    private Set<Integer> right;
    private LookupArtist lookupArtist;

    public Rule(LookupArtist lookupArtist){
        left = new HashSet<>();
        right = new HashSet<>();
        this.lookupArtist = lookupArtist;
    }

    @Override
    public boolean equals(Object another){
        Rule rule = (Rule) another;

        if(this.left.equals(rule.getLeft()) && this.right.equals(rule.getRight()))
            return true;
        else
            return false;
    }

    @Override
    public String toString(){
        /* print the object */
    }

    public void addToLeft(Integer toAdd){
        left.add(toAdd);
    }

    public void addToRight(Integer toAdd){
        right.add(toAdd);
    }

    public Set<Integer> getLeft(){
        return left;
    }

    public Set<Integer> getRight(){
        return right;
    }

}

Я также equals() метод equals() по-другому, просто чтобы попробовать:

@Override
    public boolean equals(Object another){
        Rule rule = (Rule) another;
        boolean flag = true;
        for(Integer artist : left){
            if(flag)
            if(!rule.left.contains(artist))
                flag=false;
        }

        if(flag)
            for(Integer artist : right){
                if(flag)
                if(!rule.right.contains(artist))
                    flag=false;
            }
        return flag;

    }

Объект LookupArtist используется для сопоставления целых чисел с некоторыми строками.

Проблема в том, что когда я печатаю правила, я обнаружил, что некоторые правила появляются два раза. Я также нашел в режиме отладки некоторые реплицированные правила, поэтому это не проблема печати. Правила сохраняются на карте следующим образом:

static Map<Rule, Float> rules;

.
.
.

Rule rule = new Rule(lookupArtist);
for(int j=0;j<i;j++){
    rule.addToLeft(a[j]);
}
for(int j=i;j<a.length;j++){
    rule.addToRight(a[j]);
}
if(!rules.containsKey(rule)){
    rules.put(rule, getRuleConfidence(rule));
}

Любая идея, где проблема может быть?

Теги:
equals
hashset
override
map

3 ответа

1
Лучший ответ

Вы всегда должны переопределять hashCode при переопределении equals и наоборот.

Добавьте что-то вроде этого в свой класс Rule:

@Override
public int hashCode() {
    return left.hashCode()
         ^ right.hashCode()
         ^ lookupArtist.hashCode();
}

Вот хороший ответ, объясняющий, почему важно переопределить оба.

Кроме того, ваш метод equals может быть записан как

@Override
public boolean equals(Object another){
    Rule rule = (Rule) another;
    return left.equals(rule.left)
        && right.equals(rule.right)
        && lookupArtist.equals(rule.lookupArtist);
}

Заключительное замечание: Ваша другая попытка реализации равенства не симметрична, т. rule1.equals(rule2) Это не тот случай, когда rule1.equals(rule2) тогда и только тогда, когда rule2.equals(rule1). Это нарушение договора равных.

  • 0
    большое Вам спасибо. не знал об этом :)
  • 0
    Пожалуйста.
3

При использовании HashSet для хранения объектов класса, у которого есть обычная equals реализация, вы должны иметь соответствующую специальную реализацию для hashCode.

Если два объекта равны (в соответствии с пользовательской equals реализацией ), they must have the same хэш-код . In the code you posted, я don't see an overriding of . In the code you posted, я don't see an overriding of hashCode in the Rule.

Когда вы добавляете экземпляр в HashSet, метод hashCode используется для определения индекса в хеш-таблице, в которой будет храниться экземпляр. Затем связанный список экземпляров, хранящихся в этом индексе, повторяется, чтобы увидеть, существует ли экземпляр. При повторении этого списка используется значение equals. Если два одинаковых объекта сопоставляются hashCode с разными индексами в HashSet, дублирование не будет обнаружено, поскольку они будут храниться в отдельных связанных списках.

Это указано в Джавадоке equals:

 * Note that it is generally necessary to override the <tt>hashCode</tt>
 * method whenever this method is overridden, so as to maintain the
 * general contract for the <tt>hashCode</tt> method, which states
 * that equal objects must have equal hash codes. 

И в Javadoc hashCode:

 * <li>If two objects are equal according to the <tt>equals(Object)</tt>
 *     method, then calling the <code>hashCode</code> method on each of 
 *     the two objects must produce the same integer result. 
  • 0
    спасибо, я не сделал, что карты также считают хэш-код: S
1

И где ваш метод hashCode()? Это тоже очень важно :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню