为什么要重写equals也最好重写hashCode

如题:

  为什么在重写equals的时候最好也重写hashCode?



先提一下:java编程里有关约定:如果两个对象根据equals方法比较是相等的,那么调用这两个对象的任意一个hashcode方法都必须产生相同的结果。但是hashCode相等,两个对象却不一定相等(哈希冲突)。

看不懂没关系,废话不多说,直接请你吃栗子(先说为什么重写equals再说hashCode)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

  假设现在有很多学生对象,默认情况下,要判断多个学生对象是否相等,需要根据地址判断,若对象地址相等,那么对象的实例数据一定是一样的,但现在我们规定:当学生的姓名、年龄、性别相等时,认为学生对象是相等的,不一定需要对象地址完全相同,例如学生A对象所在地址为100,学生A的个人信息为(姓名:A,性别:女,年龄:18,住址:北京软件路999号,体重:48),学生A对象所在地址为388,学生A的个人信息为(姓名:A,性别:女,年龄:18,住址:广州暴富路888号,体重:55),这时候如果不重写Object的equals方法,那么返回的一定是false不相等,这个时候就需要我们根据自己的需求重写equals()方法了。

public class Student {
    private String name;// 姓名
    private String sex;// 性别
    private String age;// 年龄
    private float weight;// 体重
    private String addr;// 地址
    
    // 重写hashcode方法
    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 17 * result + sex.hashCode();
        result = 17 * result + age.hashCode();
        return result;
    }
 
    // 重写equals方法
    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof Student)) {
       // instanceof 已经处理了obj = null的情况
            return false;
        }
        Student stuObj = (Student) obj;
        // 地址相等
        if (this == stuObj) {
            return true;
        }
        // 如果两个对象姓名、年龄、性别相等,我们认为两个对象相等
        if (stuObj.name.equals(this.name) && stuObj.sex.equals(this.sex) && stuObj.age.equals(this.age)) {
            return true;
        } else {
            return false;
        }
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getSex() {
        return sex;
    }
 
    public void setSex(String sex) {
        this.sex = sex;
    }
 
    public String getAge() {
        return age;
    }
 
    public void setAge(String age) {
        this.age = age;
    }
 
    public float getWeight() {
        return weight;
    }
 
    public void setWeight(float weight) {
        this.weight = weight;
    }
 
    public String getAddr() {
        return addr;
    }
 
    public void setAddr(String addr) {
        this.addr = addr;
    }
 
}

以上面例子为基础,即student1和student2在重写equals方法后被认为是相等的。

在两个对象已经重写equals的情况下进行把他们分别放入Map和Set中

在上面的代码基础上追加如下代码:

Set set = new HashSet();
    set.add(s1);
    set.add(s2);
    System.out.println(set);

如果没有重写Object的hashcode()方法(即去掉上面student类中hashcode方法块),这里会输出

[jianlejun.study.Student@7852e922, jianlejun.study.Student@4e25154f]

↓↓↓↓↓↓↓↓↓↓↓↓↓↓划重点↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

说明该Set容器类有2个元素。.........等等,为什么会有2个元素????刚才经过测试,s1不是已经等于s2了吗,那按照Set容器的特性会有一个去重操作,那为什么现在会有2个元素。这就涉及到Set的底层实现问题了,这里简单介绍下就是HashSet的底层是通过HashMap实现的,最终比较set容器内元素是否相等是通过比较对象的hashcode来判断的(如果HashMap的值是自定义类型且没有重写hashCode,那么也会出现逻辑上面重复的元素都成为了Key)。现在你可以试试吧刚才注释掉的hashcode方法弄回去,然后重新运行,看是不是很神奇的就只输出一个元素了

其原因很简单,因为Set在调用add()方法添加元素的时候,正是通过hashCode()方法来判断当前集合是否已经存在了重复元素。

一般重写hashCode()方法代码:

@Override
    public int hashCode() {
        int result = name.hashCode();
        result = 17 * result + sex.hashCode();
        result = 17 * result + age.hashCode();
        return result;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容