BigDecimal可以用equals方法做等值比较吗?

结论是不可以,BigDecimalequals方法不仅会比较值,还会比较精度,比如1.01.00虽然值是一样的,我们也倾向于认为是相同的,但是因为精度不同,最终得到的结论是false。 代码如下:

@Test
public void compareBigDecimal(){
    BigDecimal d1 = new BigDecimal("1.0");
    BigDecimal d2 = new BigDecimal("1.00");
    System.out.println(d1.equals(d2));
}

得到结果:

image.png

这是因为BigDecimal重写了equals方法,源码如下:

public boolean equals(Object x) {
    if (!(x instanceof BigDecimal))
        return false;
    BigDecimal xDec = (BigDecimal) x;
    if (x == this)
        return true;
    if (scale != xDec.scale)
        return false;
    long s = this.intCompact;
    long xs = xDec.intCompact;
    if (s != INFLATED) {
        if (xs == INFLATED)
            xs = compactValFor(xDec.intVal);
        return xs == s;
    } else if (xs != INFLATED)
        return xs == compactValFor(this.intVal);

    return this.inflated().equals(xDec.inflated());
}

这段代码是BigDecimal类中的equals方法的一部分,用于比较两个BigDecimal对象是否相等。以下是这段代码的详细解释:

  1. 检查对象类型:

if (!(x instanceof BigDecimal))  
    return false;

如果传入的对象x不是BigDecimal的实例,那么返回false。 2. 强制类型转换:

BigDecimal xDec = (BigDecimal) x;

将对象x强制转换为BigDecimal类型,并赋值给xDec。 3. 检查是否为同一个对象:

if (x == this)  
    return true;

如果x和this引用的是同一个对象,那么返回true。 4. 比较标度(scale):

if (scale != xDec.scale)  
    return false;

如果两个BigDecimal对象的标度(小数点后的位数)不同,那么返回false。 5. 比较紧凑值:

long s = this.intCompact;  
long xs = xDec.intCompact;  
if (s != INFLATED) {  
    if (xs == INFLATED)  
        xs = compactValFor(xDec.intVal);  
    return xs == s;  
} else if (xs != INFLATED)  
    return xs == compactValFor(this.intVal);

这部分代码比较了两个BigDecimal对象的紧凑值。紧凑值是一个用于存储小整数值的字段,当值的绝对值小于10^7时,它可以直接存储在这个字段中,而不需要使用更复杂的数据结构。如果this的紧凑值不是INFLATED(表示紧凑值有效),但xDec的紧凑值是INFLATED,那么会尝试获取xDec的紧凑值。然后,比较这两个紧凑值是否相等。 6. 比较膨胀值:

return this.inflated().equals(xDec.inflated());

如果上述比较都没有返回结果,那么这部分代码会比较两个BigDecimal对象的膨胀值。膨胀值是一个更复杂的数据结构,用于存储大于10^7的整数值或小数。这部分代码通过调用inflated()方法获取膨胀值,并使用equals方法进行比较。 重写后的equals方法实现了BigDecimal对象的等价性检查,它首先检查类型,然后检查标度,接着比较紧凑值,如果仍然不能确定等价性,最后会比较膨胀值

那可以用==比较吗?

这当然也不行,这是因为 == 运算符在 Java 中用于比较对象的引用是否相同,即是否指向内存中的同一个对象实例,而不是比较它们的内容或值。

那应该怎么做等值比较呢?

可以使用 compareTo() 方法来比较两个 BigDecimal 对象的大小关系,而不是使用 equals() 方法进行等值比较。compareTo() 方法返回一个整数值,表示两个 BigDecimal 对象的大小关系:

  • 如果第一个 BigDecimal 对象小于第二个,则返回负数;

  • 如果两个对象相等,则返回0;

  • 如果第一个 BigDecimal 对象大于第二个,则返回正数。

所以,你可以使用 compareTo() 方法来判断两个 BigDecimal 对象是否相等。如果返回的结果是0,则表示两个对象的数值相等。