JAVA学习DAY15:equals与hashCode重写

1 阅读3分钟

今天承接了昨天的悬念,学习了equals和hashCode的重写机制,终于搞懂了为什么属性相同的自定义对象在HashSet中无法去重,以及如何通过重写这两个方法让集合框架按照对象内容来判断相等。用IDEA自动生成了Product类的equals和hashCode方法,并验证了去重效果。HashMap的内容今天还没有学习,留到后面再补上。


一、为什么需要重写equals和hashCode

昨天发现两个属性完全相同的Product对象可以同时存进HashSet,根本原因是Product类继承了Object类的equals和hashCode方法,而Object默认的实现比较的是对象在内存中的地址。两个不同的对象即使内容一模一样,内存地址也不同,所以HashSet认为它们是不同的元素。

但在实际业务中,判断两个商品是否相同,应该依据它们的内容(比如名称、价格、产地等),而不是内存地址。因此必须重写equals方法,让它的比较逻辑从"比地址"变成"比内容"。

同时,HashSet和HashMap等哈希结构的内部工作流程是:先根据元素的hashCode值找到对应的存储位置(桶),只有当hashCode相同时,才会进一步调用equals方法判断是否真正相等。如果只重写equals而不重写hashCode,就会出现equals认为相等的两个对象,因为hashCode不同而被散列到不同的桶中,HashSet仍然无法正确去重。因此equals和hashCode必须同时重写,而且要保持一致:equals返回true的两个对象,hashCode必须相同。


二、equals重写的规则

重写equals方法时需要遵循几个约定。自反性:任何对象与自身比较必须返回true。对称性:如果a等于b,那么b也必须等于a。传递性:如果a等于b且b等于c,那么a必须等于c。一致性:只要对象的内容没有改变,多次比较的结果应该相同。非空性:任何对象与null比较必须返回false。

在实际开发中,手动编写equals方法不仅繁琐,还容易出错。今天学会了使用IDEA的自动生成快捷键,IDEA会根据类的属性自动编写符合规范的equals和hashCode方法,既准确又高效。


三、hashCode重写的规则

hashCode方法返回的是一个int类型的哈希码值,它的核心规则是:如果两个对象通过equals比较相等,那么它们的hashCode值必须相同。反过来不成立,hashCode相同的两个对象,equals不一定返回true,这种情况称为哈希冲突,哈希结构内部会用链表或红黑树来处理冲突。

hashCode的计算通常是将各个属性的哈希值进行组合,比如用31作为乘数进行累加。31是一个奇素数,既能减少哈希冲突的概率,又能通过位运算优化性能。IDEA自动生成的hashCode方法就遵循了这种成熟的计算方式。


四、验证去重效果

今天创建了ProductFixed类,用IDEA自动生成了equals和hashCode方法。然后再次进行昨天的测试:创建两个属性完全相同的ProductFixed对象,放入HashSet中。这次HashSet的大小变成了1,重复的对象被成功过滤掉了。这个实验让自己彻底理解了哈希结构去重的完整流程:先算hashCode定位桶,再用equals确认是否重复,两者缺一不可。