使用hashCode和equals时,HashSet.contains的行为与预期不符

时间:2011-10-20 11:40:23

标签: java hashset

我有一个名为MyClass的课程:

public class MyClass extends abstractClass implements
        someInterface {

    Set<VNode> relation_;
    Set<VNode> x_;
    Set<VNode> y_;


     @Override
    public boolean equals(Object obj) {

        if (!super.equals(obj)) {
            return false;
        }

        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof MyClass)) {
            return false;
        }
        MyClass other = (MyClass) obj;

        if (relation_ == null) {
            if (other.relation_ != null) {
                return false;
            }
        } else if (!relation_.equals(other.relation_)) {
            return false;
        }
        if (x_ == null) {
            if (other.x_ != null) {
                return false;
            }
        } else if (!x_.equals(other.x_)) {
            return false;
        }
        if (y_ == null) {
            if (other.y_ != null) {
                return false;
            }
        } else if (!y_.equals(other.y_)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int res = new HashCodeBuilder(17, 37).append(relation_).append(x_)
                .append(y_).append(getWeight()).toHashCode();

        return res;
    }
}

抽象类如下:

public abstract class abstractClass {

    double weight_;


    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof abstractClass)) {
            return false;
        }
        abstractClass other = (abstractClass) obj;
        if (Double.doubleToLongBits(weight_) != Double
                .doubleToLongBits(other.weight_)) {
            return false;
        }
        return true;
    }

    public double getWeight() {
        return weight_;
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        long temp;
        temp = Double.doubleToLongBits(weight_);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

}

现在,如果我有HashSet<MyClass> s1MyClass i1,即使s1有一个s1i元素s1i.equals(i1)=trues1i.hashCode()=i1.hashCode(),{ {1}}给了我s1.contains(i1)

有任何解释吗?

其他课程:

false

2 个答案:

答案 0 :(得分:2)

你的equals()方法根本不可读。由于您在hashCode()中使用HashCodeBuilder,为什么不使用EqualsBuilder呢?

版本a)

public boolean equals(Object obj){
    if(obj == null || obj.getClass()!=getClass()){
        return false;
    }
    MyClass other = (MyClass) obj;
    return new EqualsBuilder()
      // check parent properties first
      .append(this.getWeight(), other.getWeight())
      .append(this.relation_, other.relation_)
      .append(this.x_, other.x_)
      .append(this.y_, other.y_)
      .isEquals();
}

版本b)

public boolean equals(Object obj){
    // delegate to parent equals first
    if(!super.equals(obj)){
        return false;
    }
    MyClass other = (MyClass) obj;
    return new EqualsBuilder()
      .append(this.relation_, other.relation_)
      .append(this.x_, other.x_)
      .append(this.y_, other.y_)
      .isEquals();
}

答案 1 :(得分:1)

在计算equals和hashcode时,每个类只应关注自己的变量。因此,在MyClass中而不是调用getWeight(),您应该使用超类的哈希码。和你一样equals()!在这种情况下,效果将是相同的。

public int hashCode() {
    int res = new HashCodeBuilder(super.hashcode(), 37).append(relation_).append(x_)
            .append(y_);

    return res;
}

这意味着对可能影响equals和hashcode的基类的任何更改都局限于类,并且您不必更新子类。

(不是一个真正的答案,更多的是观察,但它的评论太大了)