简体   繁体   中英

Hashcode & equals implementation

I'm writing some code to demonstrate equals and hashcode, for my implementation I used User example :

public class User {
    private String name;
    private String pass;
    //...
    @Override
    public boolean equals(Object obj) {
        if (obj == null) { return false; }
        if (obj == this) { return true; }
        if (obj.getClass() != this.getClass()) {
            return false;
        }
        User rhs = (User) obj;

        EqualsBuilder eb = new EqualsBuilder();
        eb.append(this.getName(), rhs.getName());
        //eb.append(this.getPass(), rhs.getPass());
        return eb.isEquals();
    }
    @Override
    public int hashCode() {
        HashCodeBuilder hcb = new HashCodeBuilder(17, 37);
        hcb.append(this.getName());
        hcb.append(this.getPass());
        return hcb.toHashCode();
    }
    //...
    public static void main(String[] args) {

        User u1 = new User("foo","foo1");
        User u2 = new User("bar","bar1");
        System.out.println(u1.equals(u2));
        System.out.println(u1.hashCode() + " ?= " + u2.hashCode());
        User u3 = new User("foo","foo1");
        User u4 = new User("foo","bar1");
        System.out.println(u3.equals(u4));
        System.out.println(u3.hashCode() + " ?= " + u4.hashCode());

    }
}

Output:

false
2128613651 ?= 2129111967
true
2128615478 ?= 2214545177

I think I'm doing it wrong because my objects now can be equals but have a different hashcode (which is bad I know), but I want to make my Users equals only when their names are also equals.. And not when they have name AND pass equals.

How can I respect the conventions and have what I want to achieve? Thanks for your help/clarification :)

Generally speaking, if a field is not present in your equals() method, you shouldn't reference it in your hashCode() method.

This ensures your hashcode() result will not change more often that your equals() result does. Consider changing your method to:

@Override
public int hashCode() {
    HashCodeBuilder hcb = new HashCodeBuilder(17, 37);
    hcb.append(this.getName());
    return hcb.toHashCode();
}

That being said, it's rarely a good idea to create a non-intuitive equals() method. I would naturally assume your method would consider the password too, as might many of your future maintainers. Unit tests may be harder to write if true equality testing isn't conducted. Consider whether it would be better to create your own method, eg

public boolean usernameEquals(User other) {
  ...
}

All objects that are equals have the same hashcode. but not all object that have the same hashcode are equal.

All field you use in your hascode method should to be used in your equals method.

I wouldn't say that you are doing it wrong. As far as the contract is concerned, If 2 objects are equal, then they should have the same hashCode. If 2 objects have the same hashCode, they need not be equal

If you define the equality of 2 User instances as - They are equal, if their names are equal , then you are good to go. As far as the hashCodes are concerned, you are right, because if the hashCodes of 2 objects are not equal, then the objects are not equal.

BTW Duncan is completely right in pointing out that it's rarely a good idea to create a non-intuitive equals() method

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