【Java】equals和hashCode需要一起重写的原因

方法实现:

        equals和hashCode两个方法是属于Object基类的两个方法,我们先来看看两个方法的默认实现。

equals方法

public boolean equals(Object obj) {
        return (this == obj);
    }

        可以看到equals方法的默认实现是使用 == 比较两个对象,而对象使用 == 进行比较时比较的是两个对象在堆内存中的内存地址

hashCode方法

public native int hashCode();

        是native方法,不由Java实现,而是在运行时通过本地调用实现(默认是根据对象的内存地址生成),同时在文档中此方法有一个很重要的规范:If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result(如果两个对象通过equals方法比较后,结果是相等的,那么这两个对象分别调用hashCode方法必须得到相同的哈希码)。

        还有一个很重要的描述:It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results(如果两个对象通过equals方法比较后,结果不相等,这两个对象分别调用hashCode方法时也有可能产生相同的哈希码)。

小结

        1、经过equals方法比较后,两个对象相等,那么两个对象的哈希码一定相同。

        2、经过equals方法比较后,两个对象不相等,两个对象的哈希码不一定不相同。

方法验证:

User类

package test;
import lombok.*;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User {

    private int id;

    private String name;

    
}

        (1)重写equals,不重写hashCode

重写equals方法

    @Override
    public boolean equals(Object obj) {
        if(this == obj)
            return true;

        if(!(obj instanceof User))
            return false;

        User user = ((User) obj);
        return (this.getId() == user.getId()) && (this.getName().equals(user.getName()));
    }

测试类

package test;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

public class UserTest {
    public static void main(String[] args) {


        User user1 = new User(3,"邱淑贞");
        User user2 = new User(3,"邱淑贞");


        System.out.println(user1 == user2);
        System.out.println(user1.equals(user2));


        HashSet set = new HashSet<>();
        set.add(user1);
        set.add(user2);

        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            User user = iterator.next();
            System.out.println(user);
        }

        HashMap map = new HashMap<>();
        map.put(user1,"test1");
        map.put(user2,"test2");
        System.out.println(map.get(user1));
        System.out.println(map.get(user2));
    }
}

测试结果

【Java】equals和hashCode需要一起重写的原因_第1张图片

        1、==比较结果为false,因为比较的是对象的内存地址。

        2、equals比较结果为true,因为重写了equals方法实现,两个对象的字段都相同,判定为同一个对象。

        3、equals方法判定两个对象为同一对象,照理来说HashSet应该会进行去重操作,但迭代时仍然存在重复对象,这是因为HashSet是根据对象的哈希码进行去重操作,我们没有重写hashCode()方法,默认还是根据对象的内存地址生成哈希码。

        4、map分别存储了两个相同的对象,照理说map在调用get方法获取value时,会以最后一次put操作为准(map不允许key重复,使用相同key重复调用put方法会将value覆盖),但这里两个相同对象(equals比较相等,对象的hashCode也理应相等)却分别映射了不同的value,产生了歧义,而原因与上述一致。

        (2)既重写equals,也重写hashCode

重写hashCode方法

    @Override
    public int hashCode() {
        return this.name.hashCode();
    }

测试结果

【Java】equals和hashCode需要一起重写的原因_第2张图片

        1、HashSet去重没有问题。

        2、HashMap同一对象映射同一个value,重复put操作以最后一次为准。

你可能感兴趣的:(java,开发语言)