hashCode()与equals()

有面试官会问:你重写过 hashcode和equals 么,为什么重写equals时必须重写hashCode方法?
equals和hashCode都是Object对象中的非final方法,它们设计的目的就是被用来覆盖(override)的,所以在程序设计中还是经常需要处理这两个方法.下面我们一起来看一下,它们到底有什么区别,总结一波!

hashCode介绍

hashCode()的作用是获取哈希码,也称为散列码,它实际上是返回一个int整数,这个哈希码的作用是确定该对象在哈希表中的索引位置,hashCode()定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数.

equals介绍

equals()它的作用也是判断两个对象是否相等,
如果对象重写了equals()方法,一般比较两个对象的内容是否相等,
如果没有重写,比较两个对象的地址是否相同,价于“==”,
同样的,equals()定义在JDK的Object.java中,这就意味着Java中的任何类都包含有equals()函数.

hashCode() 和 equals() 有什么关系?

如果该类不会在HashSet、 HashTable、 HashMap等这些本质是散列表的数据结构中用到,则hashCode()和equals()两者之间是没有关系的。 
下面我们分析一下该类会在HashSet、 HashTable、 HashMap等这些本质是散列表的数据结构中用到时的关系:
equals相等的两个对象的hashcode一定相等;
equals不相等的两个对象的hashcode有可能相等.

示例代码

点击查看代码
package com.yuanxiaohao;
import java.util.*;
public class TestHashCode {
    public static void main(String[] args) {
        test();
    }
    public static void test(){
        System.out.println("######test######");
        Set<Model> set =new HashSet<Model>();
        Model a =new Model("猿小豪","20");
        Model b =new Model("猿小豪","20");
        set.add(a);
        System.out.println("a.hashCode:"+a.hashCode());
        set.add(b);
	  System.out.println("b.hashCode:"+b.hashCode());
        System.out.println(set);
    }
    public static class Model {
        private String name;
        private String age;
        public Model(String name, String age) {
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAge() {
            return age;
        }
        public void setAge(String age) {
            this.age = age;
        }
	  @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Model)) return false;
            Model model = (Model) o;
            return name.equals(model.name) &&
                    age.equals(model.age);
        }
//    @Override
//    public int hashCode() {
//        return (name+age).hashCode();
//    }
        @Override
        public String toString() {
            return "Model{" +
                    "name='" + name + '\'' +
                    ", age='" + age + '\'' +
                    '}';
        }
    }
}

运行结果

######test2######
a.hashCode:1163157884
b.hashCode:1956725890
[Model{name='猿小豪', age='20'}, Model{name='猿小豪', age='20'}]

结果分析

我们重写了Model的equals(),但是很奇怪的发现HashSet中仍然有重复元素:a和b.

为什么会出现这种情况呢?

这是因为虽然a和b的内容相等,但是它们的hashCode()不等,所以HashSet在添加a和b的时候,认为它们不相等.

HashSet的add方法源码分析

HashSet中的add方法实际调用的是HashMap中的put方法,而HashMap的put方法中,使用key作为参数,在hash方法中用key的hashCode()计算出hash值,然后在putVal方法中使用计算出的hash值进行比较,如果hash值相同,再通过equals()比较key值是否相同,如果都相同,则覆盖原有的Node对象,否则创建新的Node对象放入链表中.

总结

如果类使用在散列表的集合对象中,要判断两个对象是否相同,除了要重写equals()之外,也要按照规则重写hashCode()函数,否则会出现”equals相等的两个对象的hashcode不相等”的情况,从而在使用相关集合时,引起与自己的预期不相符的情况.

补充

至于为什么先使用hash值判断再使用equals.
个人理解:
在计算存放数组下标的过程中,hash值已经通过hashCode计算得到了,后面就可以直接拿来用了,这样就减少了equals次数,提高了效率.

posted @ 2022-04-11 21:42  DiligentCoder  阅读(207)  评论(0编辑  收藏  举报