Java学习笔记:equals()与hashCode()的正确姿势

Java学习笔记:equals()与hashCode()的正确姿势

在Java开发中,equals()与hashCode()是一对经常被问起、也经常被写错的方法。它们都定义在Object类中,几乎所有基于哈希的集合(如HashMap、HashSet、Hashtable)都依赖这两个方法共同遵守的契约。很多初学者只重写equals()却忽略hashCode(),结果把对象放进HashSet后出现“明明相等却取不出来”的诡异问题。今天我们就系统梳理一下。

首先说equals()到底在比较什么。Object默认的equals()实现比较的是引用地址,效果等同于双等号。当我们希望按业务字段判断两个对象是否逻辑相等时,就需要重写它。重写equals()必须满足四个基本性质:第一,自反性,x.equals(x)返回true;第二,对称性,若x.equals(y)为true,则y.equals(x)也为true;第三,传递性,若x.equals(y)且y.equals(z),则x.equals(z)为true;第四,一致性,在对象未被修改的前提下,多次调用结果应保持不变。另外,对任何非null的引用x,x.equals(null)必须返回false。

再说hashCode()的契约。hashCode()返回一个整数,用于给哈希表快速定位“桶”的位置。它的核心契约是:如果两个对象根据equals()判断相等,那么它们的hashCode()必须相等;反过来,hashCode()相等并不代表两个对象一定相等,这就是所谓的哈希冲突。哈希表正是先通过哈希值把对象分散到不同桶中,再用equals()在桶内做精确比对,从而实现接近常数级别的查找性能。

接下来是常见的三种错误写法。错误一:只重写equals(),不重写hashCode()。这样两个逻辑相等的对象可能算出不同的哈希值,HashMap会把他们放进不同桶,导致contains或get找不到对象。错误二:用可变字段参与哈希计算。对象的某个属性一旦改变,它在HashSet中的位置就会失效,后续查找会出错。错误三:用浮点数直接做哈希。浮点数存在精度问题,应该先转换为确定性的整数表示。

关于推荐写法,现代Java推荐使用Objects.equals()和Objects.hash()来简化实现,减少手写出错的可能。以Person类为例,重写equals()时先判断引用相同、类型匹配,再逐字段比较name和age;重写hashCode()时直接返回Objects.hash(name, age)。如果字段较多,也可以让IDE自动生成,或使用Lombok的EqualsAndHashCode注解,但要注意Lombok默认可能把父类字段排除在外,需要根据业务决定是否包含父类。

最后小结一下:记住一条原则,重写equals()时,几乎总是需要同时重写hashCode()。只有当你确定对象永远不会被放进哈希集合时,才可以暂时忽略。理解并遵守这两个方法的契约,是写出健壮、可维护Java程序的基础。希望这篇笔记能帮你少踩一个坑。

posted @ 2026-09-15 21:44  梦幻泡影Qv'Q  阅读(5)  评论(0)    收藏  举报