简体   繁体   中英

HashSet.contains does not behave as expected with hashCode and equals

I have a class called 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;
    }
}

The abstract class is as follows:

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

}

Now, if I have HashSet<MyClass> s1 and an MyClass i1 , even if s1 has an element s1i whith s1i.equals(i1)=true and s1i.hashCode()=i1.hashCode() , s1.contains(i1) gives me false .

Any explanations?

Other classes:

public class VNode {

    Mention mention_;


    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof VNode)) {
            return false;
        }
        VNode other = (VNode) obj;
        if (mention_ == null) {
            if (other.mention_ != null) {
                return false;
            }
        } else if (!mention_.equals(other.mention_)) {
            return false;
        }
        return true;
    }


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



}




public class Mention extends Range {


    private final int                           id_;


    public Mention(final int start, final int end) {
        super(start, end);

        id_ = getNextMentionID();
    }

}





public class Range {


    private final int start_;

    private final int end_;

    /**
     * Contr.
     * 
     * @param start
     * @param end
     */
    public Range(final int start, final int end) {
        start_ = start;
        end_ = end;
    }



    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Range)) {
            return false;
        }
        Range other = (Range) obj;
        if (end_ != other.end_) {
            return false;
        }
        if (start_ != other.start_) {
            return false;
        }
        return true;
    }



    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + end_;
        result = prime * result + start_;
        return result;
    }



}

Your equals() method is not readable at all. Since you are using HashCodeBuilder in hashCode(), why not use EqualsBuilder as well?

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

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

Each class should only be concerned with its own variables when calculating equals and hashcode. So, in your MyClass instead of calling getWeight() you should be using the hashcode of the super class. Like you are with equals() !. In this case the effect will be the same.

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

    return res;
}

This means any changes to the base class that may affect equals and hashcode are confined to the class and you don't have to update the sub classes.

(Not really an answer, more an observation but its too big for a comment)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM