1. 概述

在使用BigDecimal时,将数值0表示为BigDecimal对象是一项常见的任务。然而,我们常常面临两种相似方法的选择:使用BigDecimal.ZERO还是通过构造函数new BigDecimal(0)创建一个新的BigDecimal对象。

本教程将探讨这两种方法之间的微妙但重要的差异,并讨论何时选择一种而非另一种。

为了简化,我们将使用单元测试断言来验证结果。

2. 比较BigDecimal对象

在比较BigDecimal.ZEROnew BigDecimal(0)之前,让我们快速了解一下如何比较两个BigDecimal对象。

由于BigDecimal类实现了Comparable接口,我们可以使用equals()方法或compareTo()方法来比较两个BigDecimal对象。但是,这两个方法对两个BigDecimal实例进行的比较是不同的。

假设我们有两个BigDecimal对象bd1bd2。如果bd1.compareTo(bd2) == 0,它仅仅表示两个BigDecimal对象的值相等。例如,BigDecimal 42.0042.0000在值上相同,但精度不同:

BigDecimal bd1 = new BigDecimal("42.00");
BigDecimal bd2 = new BigDecimal("42.0000");
assertEquals(0, bd1.compareTo(bd2));

然而,重要的是要知道BigDecimalequals()方法基于值和精度来判断相等性。因此,使用equals()方法比较BigDecimal 42.0042.0000会导致它们被视为不相等:

BigDecimal bd1 = new BigDecimal("42.00");
BigDecimal bd2 = new BigDecimal("42.0000");

assertNotEquals(bd1, bd2);

接下来,我们使用equals()方法比较BigDecimal.ZEROnew BigDecimal(0)

BigDecimal zero = BigDecimal.ZERO;
BigDecimal zero0 = new BigDecimal(0);
assertEquals(zero, zero0);

如上述测试所示,BigDecimal.ZEROnew BigDecimal(0)在值和精度上都表现出相等性。因此,它们在数学上是相同的。在实际应用中,这意味着在计算中使用它们不会有任何可感知的区别。

接下来,让我们看看这两个对象是如何被初始化的。

3. BigDecimal.ZERO的内部工作原理

BigDecimal.ZEROBigDecimal类中的一个常量字段:

public static final BigDecimal ZERO = ZERO_THROUGH_TEN[0];

如图所示,它取自名为ZERO_THROUGH_TEN的数组的一部分:

private static final BigDecimal[] ZERO_THROUGH_TEN = {
    new BigDecimal(BigInteger.ZERO, 0,  0, 1),
    new BigDecimal(BigInteger.ONE, 1,  0, 1),
    new BigDecimal(BigInteger.TWO, 2,  0, 1),
    ...
    new BigDecimal(BigInteger.TEN, 10, 0, 2),
};

BigDecimal预先实例化了11个对象(0到10)。所以,每次使用BigDecimal.ZERO时,我们都在使用同一个对象,而无需额外的对象创建:

BigDecimal z1 = BigDecimal.ZERO;
BigDecimal z2 = BigDecimal.ZERO;
assertSame(z1, z2);

4. new BigDecimal(0)的内部工作原理

另一方面,new BigDecimal(0)通过构造函数创建一个新的BigDecimal对象,指定值为0:

public BigDecimal(int val) {
    this.intCompact = val;
    this.scale = 0;
    this.intVal = null;
}

由于它调用了构造函数,每次调用new BigDecimal(0)时,都会创建一个新的对象

BigDecimal z1 = new BigDecimal(0);
BigDecimal z2 = new BigDecimal(0);
assertNotSame(z1, z2);

5. 我们应该采取哪种方法?

BigDecimal.ZEROnew BigDecimal(0)方法都创建了不可变的BigDecimal对象,确保了线程安全性和一致性。然而,正如我们前面所说,BigDecimal.ZERO还有一个额外的优势,那就是重用共享的常量对象。当BigDecimal.ZERO在代码库的多个部分中被使用时,会使用同一个对象引用,避免了不必要的对象创建。

此外,在BigDecimal.ZEROnew BigDecimal(0)之间选择时,一个主要考虑因素是代码的清晰度和意图。BigDecimal.ZERO因为其简洁性和可读性而更受欢迎。它的自我解释性质使代码更具表达力,符合明确表示0的意图。

因此,当我们需要一个表示0的BigDecimal对象时,建议使用BigDecimal.ZERO

6. 总结

在这篇文章中,我们首先了解了BigDecimal.ZEROnew BigDecimal(0)方法如何初始化BigDecimal实例。然后,我们讨论了从可读性和对象重用的角度应选择哪种方法。

BigDecimal.ZERO因其简洁语法、清晰意图以及可能的共享对象引用而脱颖而出。所以,如果你想要一个表示0的BigDecimal对象,我们应该首选BigDecimal.ZERO

如往常一样,示例代码的完整源代码可在GitHub上找到。