Java: проблемы с TreeSet - PullRequest
       34

Java: проблемы с TreeSet

0 голосов
/ 11 октября 2009

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

public class OdpStorage {

    private TreeSet<Odp> collection = new TreeSet<Odp>(); 

    public addOdp(Odp o) {
          return collection.add(o);
    }

    public int size() {
          return collection.size();
    }

}

collection.add (Odp o) должен ничего не делать, если он уже находится в дереве, верно? Каким-то образом этот модульный тест не проходит:

OdpStorage ts = new OdpStorage();       
Odp ftw = new Odp("LOL");
    Odp ktr = new Odp("OMG");

    ts.addOdp(ftw);

    ts.addOdp(ftw); //should do nothing
    ts.addOdp(ftw); //should do nothing
    ts.addOdp(ftw); //should do nothing
    ts.addOdp(ktr);

assertEquals(2, ts.size());

Утверждение не выполняется. Ожидается 2, но возвращаемое значение - 5. Почему? Может ли быть нарушена функция odp.equals ()?

Аналогично, вызов collection.contains(o) завершается неудачно, даже если в наборе X есть объект, для которого o.equals(X) возвращает true.

Функция .equals () Odp: (генерируется Eclipse)

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Odp))
        return false;
    Gene other = (Odp) obj;
    if (sequence == null) {
        if (other.sequence != null)
            return false;
    } else if (!sequence.equals(other.sequence))
        return false;
    return true;
}

CompareTo:

/**
 * this = g0
 * if they are equal, g1 is presumed to come first
 * 
 *  @return -1 if g0 comes before g1; 1 if g0 comes after g1
 */
@Override
public int compareTo(Odp g1) {

    if (sequence.length() < g1.getSeq().length()) {
        return -1;
    }
    else if (sequence.length() > g1.getSeq().length()) {
        return 1;
    }

    if (sequence.compareTo(g1.getSeq()) < 0) {
        return -1;
    }

    return 1;
}

hashCode() не отменяется. Проблема

UPDATE hashCode() выглядит следующим образом:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
            + ((sequence == null) ? 0 : sequence.hashCode());
    return result;
}

Но это все еще не решает проблему.

Ответы [ 3 ]

3 голосов
/ 11 октября 2009

Ваша реализация compareTo никогда не возвращает 0. Она должна возвращать 0, когда экземпляры объекта равны.

1 голос
/ 11 октября 2009

Похоже, что ваш collection.add(o) не может найти объект в основе TreeMap. Ваш Odp реализует Comparable или вы устанавливаете Comparable по умолчанию для TreeSet, чей compare метод, который вы реализовали? Если это так, вам необходимо убедиться, что ваш compareTo (для Comparable) или Comparator compare метод вернет 0, если переданные объекты равны equals.

РЕДАКТИРОВАТЬ (в ответ на ваш комментарий к исходному сообщению):

Рекомендуется переопределять HashCode() всякий раз, когда вы переопределяете equals()

EDIT2 в ответ на вашу compareTo реализацию:

Если g0 и g1 равны, вы должны вернуть 0. Это корень проблемы.

0 голосов
/ 11 октября 2009

Мате убери своих равных, у него слишком много if / elses. замените его хорошим do / while большим количеством тестов условий. Если все тесты пройдены, тогда reutrn true ... Да, он получил операторы "goto", но его очень легко читать и даже легче вставлять новые условия по мере необходимости без большого количества вложений. Вложение, если / elses - зло. Использование «elses» является злом и почти всегда не нужно.

@Override
public boolean equals(final Object object) {
    boolean equals = false;

    do {
        if (this == object) {
            equals = true;
            break;
        }
        if (false == super.equals(object)) {
            break;
        }
        final DocumentView view = Unsafe.cast(object);
        if (false == this.document.equals(view.document)) {
            break;
        }
        if (this.revision != view.revision) {
            break;
        }
        if (false == this.user.equals(view.user)) {
            break;
        }
        if (false == this.timestamp.equals(view.timestamp)) {
            break;
        }
        equals = true;
    } while (false);

    return equals;
}
...