1. 概述
在使用BigDecimal
时,将数值0表示为BigDecimal
对象是一项常见的任务。然而,我们常常面临两种相似方法的选择:使用BigDecimal.ZERO
还是通过构造函数new BigDecimal(0)
创建一个新的BigDecimal
对象。
本教程将探讨这两种方法之间的微妙但重要的差异,并讨论何时选择一种而非另一种。
为了简化,我们将使用单元测试断言来验证结果。
2. 比较BigDecimal
对象
在比较BigDecimal.ZERO
和new BigDecimal(0)
之前,让我们快速了解一下如何比较两个BigDecimal
对象。
由于BigDecimal
类实现了Comparable
接口,我们可以使用equals()
方法或compareTo()
方法来比较两个BigDecimal
对象。但是,这两个方法对两个BigDecimal
实例进行的比较是不同的。
假设我们有两个BigDecimal
对象bd1
和bd2
。如果bd1.compareTo(bd2) == 0
,它仅仅表示两个BigDecimal
对象的值相等。例如,BigDecimal 42.00
和42.0000
在值上相同,但精度不同:
BigDecimal bd1 = new BigDecimal("42.00");
BigDecimal bd2 = new BigDecimal("42.0000");
assertEquals(0, bd1.compareTo(bd2));
然而,重要的是要知道BigDecimal
的equals()
方法基于值和精度来判断相等性。因此,使用equals()
方法比较BigDecimal
42.00
与42.0000
会导致它们被视为不相等:
BigDecimal bd1 = new BigDecimal("42.00");
BigDecimal bd2 = new BigDecimal("42.0000");
assertNotEquals(bd1, bd2);
接下来,我们使用equals()
方法比较BigDecimal.ZERO
和new BigDecimal(0)
:
BigDecimal zero = BigDecimal.ZERO;
BigDecimal zero0 = new BigDecimal(0);
assertEquals(zero, zero0);
如上述测试所示,BigDecimal.ZERO
和new BigDecimal(0)
在值和精度上都表现出相等性。因此,它们在数学上是相同的。在实际应用中,这意味着在计算中使用它们不会有任何可感知的区别。
接下来,让我们看看这两个对象是如何被初始化的。
3. BigDecimal.ZERO
的内部工作原理
BigDecimal.ZERO
是BigDecimal
类中的一个常量字段:
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.ZERO
和new BigDecimal(0)
方法都创建了不可变的BigDecimal
对象,确保了线程安全性和一致性。然而,正如我们前面所说,BigDecimal.ZERO
还有一个额外的优势,那就是重用共享的常量对象。当BigDecimal.ZERO
在代码库的多个部分中被使用时,会使用同一个对象引用,避免了不必要的对象创建。
此外,在BigDecimal.ZERO
和new BigDecimal(0)
之间选择时,一个主要考虑因素是代码的清晰度和意图。BigDecimal.ZERO
因为其简洁性和可读性而更受欢迎。它的自我解释性质使代码更具表达力,符合明确表示0的意图。
因此,当我们需要一个表示0的BigDecimal
对象时,建议使用BigDecimal.ZERO
。
6. 总结
在这篇文章中,我们首先了解了BigDecimal.ZERO
和new BigDecimal(0)
方法如何初始化BigDecimal
实例。然后,我们讨论了从可读性和对象重用的角度应选择哪种方法。
BigDecimal.ZERO
因其简洁语法、清晰意图以及可能的共享对象引用而脱颖而出。所以,如果你想要一个表示0的BigDecimal
对象,我们应该首选BigDecimal.ZERO
。
如往常一样,示例代码的完整源代码可在GitHub上找到。