Java:TreeSet 的问题

发布于 2024-08-06 21:18:25 字数 2147 浏览 5 评论 0原文

我有一堂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) 也是如此> 返回真。

Odp 的 .equals() 函数:(由 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() 未被覆盖。问题?

更新 hashCode()如下:

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

但这仍然不能解决问题。

I have a class Odp. I want to use TreeSet to keep a sorted collection of Odp objects. However, I've been having problems.

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) is supposed to do nothing if it's already in the tree, right? Somehow, this unit test fails:

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

The assertion fails. It expects 2, but the return value is 5. Why? Could the odp.equals() function be messed up?

Similarly, calling collection.contains(o) fails, even when the there is an object in the set X for which o.equals(X) returns true.

The .equals() function of Odp: (generated by 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() is not overridden. Problem?

UPDATE
hashCode() is as follows:

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

But that still doesn't solve the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

青衫儰鉨ミ守葔 2024-08-13 21:18:25

您的 compareTo 实现永远不会返回 0。当对象实例相等时,它应该返回 0。

Your compareTo implementation never returns 0. It should return 0 when the object instances are equal.

疾风者 2024-08-13 21:18:25

您的 collection.add(o) 似乎无法在支持的 TreeMap 中找到该对象。您的 Odp 是否实现了 Comparable,或者您是否在 TreeSet 上设置了默认的 Comparable,其 compare 你已经实现的方法?如果是这样,您需要确保您的 compareTo (对于 Comparable)或您的 Comparator compare 方法如果传入的对象等于,则返回0

编辑(回应您对原始帖子的评论):

建议 每当您重写 equals()

EDIT2 以响应您的 compareTo 实现时,您都会重写 HashCode()

如果 g0g1相等,你应该返回0。这就是问题的根源。

It appears that your collection.add(o) is failing to find the object in the backing TreeMap. Does your Odp implement Comparable or are you setting a default Comparable on your TreeSet whose compare method you have implemented? If so, you will need to ensure that your compareTo (for the Comparable), or your Comparator compare method will return 0 if the objects passed in are equals.

EDIT (in response to your comment to the original post):

It is recommended that you override HashCode() whenever you override equals()

EDIT2 in response to your compareTo implementation:

If g0 and g1 are equal, you should return 0. This is the root of the problem.

苏辞 2024-08-13 21:18:25

配合清理你的平等者,它有太多的 if/else。用带有大量条件测试的漂亮 do/while 替换它。如果所有测试都通过,则 reutrn true...是的,它有“goto”语句,但它非常易于阅读,甚至更容易根据需要插入新条件,而无需大量嵌套。嵌套 if/else 是邪恶的。使用“else”是邪恶的,而且几乎总是不需要的。

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

Mate cleanup your equals, its got too many if/elses. replace it with a nice do/while with lots of condition tests. If all the tests pass then reutrn true...Yes its got "goto" statements but its very easy to read and even easier to insert new conditions as necessary without lots of nesting. Nesting if/elses is evil. Using "elses" is evil and almost always never needed.

@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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文