重写equals必须先校验null和类型,再转型;用getclass()保证类型严格匹配,instanceof支持继承但需父类正确实现;泛型嵌套类优先用带泛型的instanceof或objects.equals安全比较字段。

重写 equals 时,类型转换报错(如 ClassCastException)几乎都源于没做前置校验就强行转型。核心不是“怎么转”,而是“该不该转”和“在什么条件下才安全地转”。
必须先做 null 和类型双重检查
转型前不验证参数有效性,等于主动抛异常。标准流程是:
- 第一步:用
obj == null立即返回false—— 防止后续任何操作触发 NPE 或转型失败 - 第二步:用
getClass() != obj.getClass()或obj instanceof Xxx判定类型 - 只有这两步都通过,才能执行
Xxx that = (Xxx) obj;
注意:instanceof 对 null 返回 false,但它不能替代显式 == null 检查,因为非空性是 equals 的强制契约,需主动声明而非依赖操作符隐式行为。
选 getClass() 还是 instanceof?看继承需求
两者语义不同,直接影响子类调用是否安全:
- 用
getClass() != obj.getClass():严格要求同一运行时类,适合“不希望子类实例与父类实例相等”的场景(如值对象要求精确类型匹配) - 用
!(obj instanceof Xxx):允许子类实例参与比较,但必须确保父类equals实现本身已正确支持继承(否则会破坏对称性或传递性) - 若子类要重写
equals,调用super.equals(obj)时传入的必须是原始obj,不是转型后的that,否则父类内部getClass()检查会失败
泛型嵌套类要避免 unchecked cast 警告
比如 LinkedList.Node 这类泛型内部类,在 equals 中转型常被警告。安全做法是:
- 用带泛型信息的
instanceof判断:例如obj instanceof LinkedList>.Node(Java 14+ 支持),或退而求其次用obj instanceof LinkedList.Node+ 注释说明泛型擦除限制 - 不依赖强制转型结果做关键逻辑,字段比较优先用
Objects.equals(),它对任意引用都安全 - 若确实需泛型类型精度,可考虑将嵌套类提取为静态泛型类,脱离外围类泛型影响
字段比较别碰裸 .equals(),统一用 Objects.equals
即使类型检查通过,字段本身也可能为 null。手写 a.equals(b) 或 a == b 都有风险:
-
name.equals(other.name):任一name为null就 NPE -
name == other.name:语义错误,变成引用比较 - 正确写法:
Objects.equals(name, other.name)—— 内部自动处理null,等价于安全的三元判断
基本类型字段(int、boolean 等)可直接用 ==,无需额外防护。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











