<p>Java中Object.equals()默认不处理浮点精度问题,应使用容差比较(如Math.abs(a - b) < epsilon)替代==判断,避免因二进制误差导致逻辑相等的浮点数被判为不等。</p>

Java 中 Object.equals() 默认不处理浮点数精度问题,直接用 == 比较 float 或 double 会因二进制表示误差导致本该“逻辑相等”的值被判定为不等。解决的关键不是重写 equals 时硬套 ==,而是用**容差比较(epsilon comparison)**替代精确相等判断。
重写 equals 时避免直接 == 比较浮点字段
若类中包含 float 或 double 字段,在 equals(Object o) 实现中不能写 this.value == other.value。应改用带误差范围的比较方式:
- 对
double字段,用Math.abs(a - b) 判断(如 <code>1e-10) - 对
float字段,用Float.compare(a, b) == 0更安全(它按 IEEE 754 处理NaN和符号零),或用Math.abs(a - b) - 务必先判空、类型、引用相等,再进入字段比较逻辑
优先使用 JDK 提供的工具方法
Java 从 1.8 起提供更健壮的浮点比较工具:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Double.equals(Double a, Double b):自动处理null、NaN和 ±0,内部用Double.doubleToLongBits比较位模式,语义上等价于“数值相等”(0.0 == -0.0返回true,但Double.NaN == Double.NaN为false;而此方法让NaN与NaN相等) -
Float.equals(Float a, Float b)同理 - 注意:这些是静态方法,适用于包装类型字段;原始类型仍需手动容差或转包装后调用
根据业务场景选择合适的 epsilon 值
固定 1e-6 或 1e-10 并非万能:
立即学习“Java免费学习笔记(深入)”;
- 若数值本身量级很大(如
1e8),绝对误差1e-6可能过严;可改用相对误差:Math.abs(a - b) - 科学计算常用
ULP(Unit in the Last Place),JDK 提供Math.ulp(double)获取最小精度单位,适合高精度场景 - 业务系统中建议明确约定误差范围(如金额保留两位小数,用
Math.round(x * 100) == Math.round(y * 100)更直观)
配合 hashCode 保持契约一致
若重写了 equals 且涉及浮点字段,则 hashCode 必须同步调整,否则违反“相等对象必须有相同哈希码”原则:
- 不要对原始浮点字段直接调用
Double.hashCode(d)(它返回位模式哈希,0.0和-0.0不同) - 推荐:先将浮点值归一化(如用
Double.doubleToLongBits(d)得到位表示,它让0.0和-0.0结果一致,NaN也统一),再参与哈希计算 - 示例:
Objects.hash(name, Double.doubleToLongBits(value))

















