非空性要求x.equals(null)恒返false且不抛异常,一致性要求字段不变时结果稳定;二者共同保障jvm集合正常工作,需用==判空、objects.equals防null并保一致、getclass()类型检查及equals与hashcode字段同步。

一致性与非空性是重写 equals 方法时两个不可妥协的契约。它们不是“可选优化”,而是 JVM 集合类(如 HashMap、HashSet)正常工作的前提。违反任一,都可能造成对象查不到、重复添加、逻辑断言失败等隐蔽问题。
非空性:确保 x.equals(null) 永远返回 false
这是最基础也最容易被跳过的防线。规范明确要求:对任意非 null 的 x,x.equals(null) 必须返回 false,且不能抛 NullPointerException。
- 第一步必须是显式判空:
if (obj == null) return false; - 必须用
==判断,绝不能用.equals()——后者在 null 上直接崩溃 - 这行代码要放在方法最开头,早于任何转型、字段访问或类型检查
- 注意:仅靠
instanceof不足以满足契约。虽然null instanceof Xxx返回false,但它属于“被动兜底”,而非主动声明语义。规范强调的是“必须保证”,不是“恰好不崩”
一致性:结果稳定,不随时间或调用次数变化
一致性指:只要参与比较的字段没变,多次调用 x.equals(y) 就必须始终返回相同结果(true 或 false)。它被破坏往往源于隐式状态变更或不确定值参与比较。
- 禁止在
equals方法中修改对象状态(例如触发懒加载、计算缓存字段、调用 setter) - 避免使用易变或非确定性字段:比如
new Date()、System.nanoTime()、未归一化的浮点数(应改用Double.compare(a, b) == 0) - 集合类字段(如
List、Set)要用Objects.equals或Arrays.equals,它们内部已保证遍历顺序和比较逻辑稳定 - 如果字段本身是自定义对象,确保其
equals也满足一致性——否则污染会逐层传递
二者协同的关键细节
非空性和一致性不是孤立的,它们常在同一个操作中被同时考验:
- 引用字段比较一律用
Objects.equals(a, b):它既防 null(满足非空性),又保证比较逻辑纯且稳定(支撑一致性) - 类型检查推荐
getClass() != obj.getClass()而非instanceof:前者防止子类实例与父类实例不对称相等,间接维护对称性与传递性,从而守住一致性的边界 - 所有参与
equals的字段,必须 100% 同样参与hashCode计算(例如全用Objects.hash(f1, f2, f3)):否则即使equals自身一致,放入哈希容器后行为也会“看似不一致”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











