Skip to content

BigDecimal的equals方法探秘 🔍

首先:BigDecimal重写过equals吗?

答案是:Yes! BigDecimal确实重写了Objectequals()方法,但这个重写可能和你想的不太一样...

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

为什么?

BigDecimalequals()实现要求:

  1. 数值相等(这很合理)
  2. 精度(scale)相同(这就是坑!)
  3. 非规范化的科学计数法表示也要一致

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认为它们不同

为什么这样设计? 🤔

  1. 数学精确性BigDecimal认为2.02.00在数学上是不同的表示
    • 2.0表示精度到十分位
    • 2.00表示精度到百分位
  2. 哈希一致性equals()hashCode()必须一致
  3. 符合IEEE 754浮点算术规范

正确比较方式 ✅

  1. 只比较数值

    java
    bd1.compareTo(bd2) == 0
  2. 统一精度后再比较

    java
    bd1.stripTrailingZeros().equals(bd2.stripTrailingZeros())
  3. 使用工具方法

    java
    public static boolean equalsNumerically(BigDecimal a, BigDecimal b) {
        return a.compareTo(b) == 0;
    }
  4. 高性能写法 💨

    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()是个有原则但可能过于严格的伙伴!💰

技术漫游

本站访客数 人次 本站总访问量