BigDecimal的equals方法探秘 🔍
首先:BigDecimal重写过equals吗?
答案是:Yes! BigDecimal
确实重写了Object
的equals()
方法,但这个重写可能和你想的不太一样...
equals()的"双重标准" ⚖️
先看这段让人意外的代码:
java
BigDecimal d1 = new BigDecimal("2.0");
BigDecimal d2 = new BigDecimal("2.00");
System.out.println(d1.equals(d2)); // false!什么鬼?
System.out.println(d1.compareTo(d2) == 0); // true
为什么?
BigDecimal
的equals()
实现要求:
- 数值相等(这很合理)
- 精度(scale)相同(这就是坑!)
- 非规范化的科学计数法表示也要一致
而compareTo()
只关心数值大小是否相等
源码解析 🔬
java
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
// 1. 检查数值是否相同
if (xDec.scale != scale)
return false;
// 2. 检查非规范化表示
if (this.intCompact != INFLATED) {
return (xDec.intCompact != INFLATED
&& this.intCompact == xDec.intCompact);
} else {
return this.inflate().equals(xDec.inflate());
}
}
实际应用中的坑 💣
java
Set<BigDecimal> set = new HashSet<>();
set.add(new BigDecimal("1.0"));
set.add(new BigDecimal("1.00"));
System.out.println(set.size()); // 输出2!因为equals认为它们不同
为什么这样设计? 🤔
- 数学精确性:
BigDecimal
认为2.0
和2.00
在数学上是不同的表示2.0
表示精度到十分位2.00
表示精度到百分位
- 哈希一致性:
equals()
和hashCode()
必须一致 - 符合IEEE 754浮点算术规范
正确比较方式 ✅
只比较数值:
javabd1.compareTo(bd2) == 0
统一精度后再比较:
javabd1.stripTrailingZeros().equals(bd2.stripTrailingZeros())
使用工具方法:
javapublic static boolean equalsNumerically(BigDecimal a, BigDecimal b) { return a.compareTo(b) == 0; }
高性能写法 💨
java// 既要精度安全又要性能?试试这个! public static boolean softEquals(BigDecimal a, BigDecimal b) { return a == b || (a != null && b != null && a.stripTrailingZeros().equals(b.stripTrailingZeros())); }
▸ 黑科技解释:先尝试用
==
快速判断,再统一去除末尾零后比较
特别注意事项 ⚠️
java
new BigDecimal("2.0").equals(new BigDecimal("2")) // false
new BigDecimal("2.0").equals(new BigDecimal(2.0)) // 更危险!浮点构造问题
最佳实践:永远使用String构造BigDecimal!
总结表 📊
比较方式 | 比较内容 | 示例("2.0" vs "2.00") |
---|---|---|
equals() | 数值+精度+表示形式 | false |
compareTo() | 仅数值大小 | true |
== | 对象地址 | 通常false |
记住:在金融计算中,compareTo()
才是你真正的朋友!equals()
是个有原则但可能过于严格的伙伴!💰