Object类的equals和hashCode不会递归,因其分别采用引用比较和JVM原生实现,无方法调用链;递归风险源于错误重写,如误调父类或循环引用。

不会发生无限递归。Object 类本身的 equals 和 hashCode 方法是最终实现,不调用子类重写的方法,因此不存在递归风险。
为什么 Object 的默认实现不会递归
Object 类中:
-
equals(Object obj)直接用this == obj比较引用,不调用任何其他 equals 方法; -
hashCode()是 native 方法,由 JVM 底层实现(如基于对象头 Mark Word 中缓存的哈希值),不涉及 Java 层代码调用,更不会调用子类重写版本。
这两个方法是“终点”,没有向上或向下委托逻辑,所以天然规避了递归可能。
真正容易出递归的地方是你自己重写时写错了
常见错误写法会引发栈溢出,比如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 在重写的
equals里直接调用super.equals(obj),而父类又没重写、最终回到 Object —— 这本身不递归,但若父类是自定义类且其equals又误调了当前类的方法,就可能形成闭环; - 在
equals或hashCode中意外调用了本类另一个也依赖 equals/hashCode 的方法(例如某个 getter 内部做了 deepEquals); - 字段是自身类型的集合或引用,
equals中未加 null 判断或循环引用检测,导致比较时反复进入同一对象链。
安全重写的三个关键习惯
避免你自己的实现陷入递归或死循环:
- 用
this == obj快速返回,这是最前置的自反性检查,不触发任何其他逻辑; - 类型判断用
getClass() == obj.getClass()而非instanceof,防止子类误入父类 equals 导致不对称调用; - 字段比较统一用
Objects.equals(a, b)和Objects.hash(...),它们内部已处理 null 和基础类型,不会因字段为空或循环引用而意外递归。
循环引用场景要额外小心
如果两个对象互相持有对方引用(如 A → B 且 B → A),直接用 Objects.equals 比较字段仍会栈溢出。此时需:
- 在 equals 中对已参与比较的对象做 ThreadLocal 或 Set 记录,检测重复进入;
- 或改用基于 ID 或不可变标识的比较,避开引用字段本身;
- 设计上尽量避免双向强引用,改用弱引用或解耦结构。

















