散列集合类存入对象的时候必须重写equal和hashCode方法

160 阅读1分钟

散列集合类存入对象的时候必须重写equal和hashCode方法

看hashmap和hashtable中的putVal方法中都有

//hashmap中
if (e.hash == hash &&
    ((k = e.key) == key || (key != null && key.equals(k))))
    break;
p = e;
//hashtable中
if ((entry.hash == hash) && entry.key.equals(key)) {
    V old = entry.value;
    entry.value = value;
    return old;
}

意思是如果这个对象的的hash和key相同就覆盖原来的值(hashmap多了直接对key进行判断地址),如果不重写hashcode方法就是这个对象的地址进行计算得到散列码

执行以下代码:

public static void main(String[] args) {

    User User1 = new User("用户1", 21);
    User User2 = new User("用户1", 22);
    User User3 = new User("用户1", 21);

    HashSet<User> set = new HashSet<>();
    set.add(User1);
    set.add(User2);
    set.add(User3);

    System.out.println(User1.hashCode());
    System.out.println(User2.hashCode());
    System.out.println(User3.hashCode());
    set.forEach(x -> System.out.println(x.name + " " + x.age));
}

image.png 正常来说,应该只有两个对象,就是有因为我们没有重写equal和hashcode方法,导致集合认为这是三个不同的对象,他们的hashcode也个不相同

现在我们重写hashcode和equal方法

@Override
public int hashCode() {
    return Objects.hash(name, age);
}
@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    User user = (User) o;
    return Objects.equals(name, user.name) &&
            Objects.equals(age, user.age);
}

再次执行:

image.png

@EqualsAndHashCode

这个也会去重写equal和hashcode方法,而且判断条件也更加严格

public int hashCode() {
    int PRIME = true;
    int result = 1;
    Object $age = this.age;
    int result = result * 59 + ($age == null ? 43 : $age.hashCode());
    Object $name = this.name;
    result = result * 59 + ($name == null ? 43 : $name.hashCode());
    return result;
}
public boolean equals(final Object o) {
    if (o == this) {
        return true;
    } else if (!(o instanceof User)) {
        return false;
    } else {
        User other = (User)o;
        if (!other.canEqual(this)) {
            return false;
        } else {
            Object this$age = this.age;
            Object other$age = other.age;
            if (this$age == null) {
                if (other$age != null) {
                    return false;
                }
            } else if (!this$age.equals(other$age)) {
                return false;
            }

            Object this$name = this.name;
            Object other$name = other.name;
            if (this$name == null) {
                if (other$name != null) {
                    return false;
                }
            } else if (!this$name.equals(other$name)) {
                return false;
            }

            return true;
        }
    }
}