走心解答hashCode与equals,尽量说明白
首先说结论:通过 共同使用hashcode和equals方法 来判断两个对象是否相等。
首先明确:在实际情况下,比较两个对象是否相等,我们关注的是每个对象的属性值是否都相同。
所以在比较前先要重写hashcode和equals方法。
那为什么要重写它们呢?
- 为什么重写hashcode:因为hashcode默认是Object中的方法,默认比较的是对象的地址值(即使new出来的两个对象属性值都一样,按理说两个对象是相等的,但new出的对象之间的地址不一样),所以我们需要通过在javabean中重写hashcode方法来让其根据对象的属性值去计算对应的hashcode。
[需要注意的是:重写过hashcode方法并不代表万事大吉不会出现问题,由于哈希冲突的存在导致,实际工作中还要结合equals去判断对象是否相等,下面会有具体解释。也可以联系集合中哈希表存储元素的过程。] - 为什么重写equals:而equals默认也是Object中的方法,底层使用“==”去比较对象。对于“==”我们知道:如果是基本数据类型比较的是值是否相等;如果是非基本数据类型(即引用类型)比较的是地址值是否相同。而我们在实际情况(/实际开发)中,需要比较的对象往往是引用类型的,所以需要重写equals方法去比较每个对象的各个属性值是否相同。[需要注意的是:一些包装类型和String类等,都对equals方法进行了重写,它们比较的是对象的值是否相等]
为什么要同时使用 重写后的hashcode 和 重写后的equals 方法 共同去判断两个对象是否相等呢?
- 如果只使用重写后的hashcode:
- 即使已经重写过,两个属性值不一样的对象,它们的hashcode也可能是一样的(哈希碰撞/哈希冲突)。【实际两个对象并不一样,所以不能只使用hashcode方法去判断 两个对象是否相等】
// eg:
String s1 = "通话";// 两个值不同的字符数组对象
String s2 = "重地";
System.out.println(s1.hashCode() == s2.hashCode());// 用重写后的hashCode去比较的结果竟然是trueString s3 = "abc";
String s4 = "acD";
System.out.println(s3.hashCode() == s4.hashCode());// trueString s5 = "3C";
String s6 = "2b";
System.out.println(s5.hashCode() == s6.hashCode());// true
- 如果只使用重写后的equals:
- 如果不需要向底层结构是哈希表的集合中存储,只是简单比较,那么只用重写后的equals去比较两个对象是否相等完全ok。【理论可行,但实际还是建议搭配重写后的hashcode方法使用】
- 但是,但是,如果要向底层结构是哈希表的集合中存储,就必须配合使用重写后的hashcode方法。为什么呢?因为不重写hashcode,在向底层结构是哈希表的集合中存储时,默认会去调用Object中原始的hashcode方法,虽然两个属性值一样的对象我们认为它们是相等的,但计算后得出的hashcode却不一样,按照java该系列集合的底层逻辑,这两个对象会被存储在数组的不同位置,相当于两个一样的对象存储了两次。这显然与java该系列集合的设计思想不符:对于hashset而言,不允许有重复的元素;对于hashmap而言,不允许同一个key对应多个value。
所以我们得出结论:比较两个对象是否相等,需要同时重写equals方法和hashcode方法。
hashcode/哈希值/哈希码/散列码
1、2、3、4
👍👍👍