【Java】超严谨论证:为什么自定义类对象存储到Set集合中,要重写hashCode方法和equals方法

前言

首先看一下Set集合在存储元素的时候,判断元素是否重复的方法:

  1. add方法首先调用元素的hashCode方法获取该元素的哈希值,再判断Set集合中有没有元素的哈希值与之重复。如果没有,就会把新的元素存储到数组中。
  2. 如果有重复的哈希值(哈希冲突),再调用元素的equals方法和Set中已有的哈希值相同的元素进行比较:
    如果equals方法返回true,认定两个元素相同,就不会把新元素存储到集合中;
    如果equals方法返回false,则认定两个元素内容不同,就会把新元素存储到集合中,放在同一个哈希值下形成链表。

那么如果一个自定义类对象不重写hashCode方法和equals方法就add到Set集合中,会发生什么情况?

  PS:论证之前需理解“哈希冲突”的概念,可参考我之前写的一篇文章。简单地说就是字符串“重地”和“通话”的哈希值是相同的。

论证

  假设有两个不同的自定义类对象p1、p2:

  1. 自定义类没有重写hashCode方法:
      • p1、p2存储的数据相同,p1、p2哈希值不同(这时不再调用对象的equals方法),两者都能存储到Set集合中(不合理,Set集合元素不能重复)。
        注:1. 如果自定义类没有重写hashCode方法,无论p1、p2存储的数据相同或不相同(或者是”重地”和”通话”的情况),p1、p2的哈希值都不同。2. Set集合的add方法直接通过调用元素的hashCode方法就已经判断出p1、p2都能存储到集合中,就不再调用对象的equals方法了,所以重不重写equals方法对结果无影响。
      • p1、p2存储的数据不同,p1、p2哈希值不同(这时不再调用对象的equals方法),两者都能存储到Set集合中(合理)。

  2. 自定义类重写了hashCode方法,但没有重写equals方法:
      • p1、p2存储的数据相同,p1、p2哈希值相同,但是因为p1、p2的“物理”地址值不同,所以p1.equals(p2)返回false,两者任都能存储到Set集合中(不合理)。
        注:1. IDEA默认的重写hashCode方法的返回值是根据类的每一个成员变量的哈希值综合生成的,所以不同对象若存储的数据相同,则哈希值一定相同。2. 没有重写equals方法的话,equals比较的就是真实“物理”地址值 !3. 不同对象的真实“物理”地址值一定是不同的(一定是存放在内存中的不同地址)。
      • p1、p2存储的数据不同,哈希值不同(这时不再调用对象的equals方法),两者都能存储到Set集合中(合理)。
        注:极少情况下p1、p2存储的数据不同但哈希值相同(如”重地”和”通话”),这时调用对象的equals方法,因为没有重写equals方法,所以p1.equals(p2)返回false,所以p1、p2任都能存储到Set集合中(合理)。

  3. 自定义类重写了hashCode方法和equals方法
      • p1、p2存储的数据相同,p1、p2的哈希值相同,p1.equals(p2)返回true,两者都不能存储到Set集合中(合理)。
        注:重写自定义类的equals方法,p1.equals(p2)比较的是对象的内容。
      • p1、p2存储的数据不同,p1、p2的哈希值不同(这时不再调用对象的equals方法),两者都能存储到Set集合中(合理)。
        注:极少情况下p1、p2存储的数据不同但哈希值相同(如”重地”和”通话”),这时调用对象的equals方法,因为equals方法已重写,所以p1.equals(p2)返回false,两者都能存储到Set集合中(合理)。

  可以看到,第三点在任意情况下的结果都是“合理”,这就是为什么自定义类对象存储到Set集合中,要重写hashCode方法和equals方法。
    注:1. 不管自定义类有没有重写hashCode方法和equals方法,p1 == p2返回的都是false,因为对象之间的”==”比较的是对象的“物理”地址值,不是哈希值或内容,两个不同对象的物理地址值一定不同(无论对象存储的数据是否相等,或是”重地”和”通话”的情况)。2. 重写hashCode方法和equals方法很简单,IDE中快捷键ALT+Ins->equals( ) and hashCode( )。

相关文章推荐

  【Java】哈希值相同的变量/对象的地址值也相同吗?

————————— 本文结束 感谢您的阅读 —————————
谢谢你请我喝咖啡ლↂ‿‿ↂლ(支付宝扫一扫即可领红包, 消费时可抵现! 你省钱, 我赚钱, 多谢支持~)