1. 概述
在这个教程中,我们将探讨在Java中将Long
转换为BigDecimal
的两种有效方法。
2. 问题介绍
当我们谈论将Long
转换为BigDecimal
时,有些人可能会认为两者都属于Number
类型,所以我们可能可以像这样进行类型转换:BigDecimal bd = (BigDecimal) longValue;
然而,这行代码无法编译:
java: incompatible types: java.lang.Long cannot be converted to java.math.BigDecimal
接下来,让我们一起探索几种将Long
转换为BigDecimal
的方法。
为了简化,我们将使用单元测试断言来验证每种方法是否按预期工作。
3. 使用BigDecimal
构造函数
BigDecimal
类提供了一个接受long
值并创建BigDecimal
实例的构造函数。现在,让我们编写一个测试来检查这种方法是否满足我们的需求:
Long num4 = 4L;
BigDecimal result4 = new BigDecimal(num4);
assertEquals(new BigDecimal("4"), result4);
Long num42 = -42L;
BigDecimal result42 = new BigDecimal(num42);
assertEquals(new BigDecimal("-42"), result42);
如我们所见,我们测试了正负Long
值。调用构造函数后,我们得到了预期的BigDecimal
对象。
4. 使用BigDecimal.valueOf()
方法
BigDecimal
类还提供了一个静态方法,可以从给定的long
值创建BigDecimal
对象:BigDecimal.valueOf()
。
接下来,让我们看看如何使用这个方法:
Long num4 = 4L;
BigDecimal result4 = BigDecimal.valueOf(num4);
assertEquals(new BigDecimal("4"), result4);
Long num42 = -42L;
BigDecimal result42 = BigDecimal.valueOf(num42);
assertEquals(new BigDecimal("-42"), result42);
5. 如何选择?
我们已经看到了两种从long
值创建BigDecimal
对象的方法:BigDecimal(long val)
构造函数和BigDecimal.valueOf(long val)
静态方法。有人可能会问,当我们需要将Long
转换为BigDecimal
时,应该选择哪个方法?
首先回答这个问题:我们应该优先选择静态方法。 接下来,我们将理解为什么静态方法是一个更好的选择。
为了理解这两种方法之间的差异,让我们看看valueOf()
方法的实现:
public static BigDecimal valueOf(long val) {
if (val >= 0L && val < (long)ZERO_THROUGH_TEN.length) {
return ZERO_THROUGH_TEN[(int)val];
} else {
return val != Long.MIN_VALUE ? new BigDecimal((BigInteger)null, val, 0, 0) : new BigDecimal(INFLATED_BIGINT, val, 0, 0);
}
}
如代码所示,方法会检查给定的long
值是否在0到10之间,如果是,则从数组ZERO_THROUGH_TEN
中返回相应的元素。
接下来,让我们看看ZERO_THROUGH_TEN
数组的内容:
public class BigDecimal ... {
...
private static final BigDecimal[] ZERO_THROUGH_TEN;
...
static {
ZERO_THROUGH_TEN = new BigDecimal[]{
new BigDecimal(BigInteger.ZERO, 0L, 0, 1),
...
new BigDecimal(BigInteger.valueOf(9L), 9L, 0, 1),
new BigDecimal(BigInteger.TEN, 10L, 0, 2)};
...
...}
}
如图所示,ZERO_THROUGH_TEN
是一个static BigDecimal
数组,在静态初始化块中初始化。因此,**BigDecimal
类会在ZERO_THROUGH_TEN
数组中缓存0到10的值**。
所以,当调用BigDecimal.valueOf()
时,如果long
值在0到10之间,valueOf()
会立即从ZERO_THROUGH_TEN
数组中返回缓存的对象。否则,它会构造一个新的BigDecimal
对象。
接下来,通过测试来验证这一点:
Long num4 = 4L;
BigDecimal bd4_1 = BigDecimal.valueOf(num4);
BigDecimal bd4_2 = BigDecimal.valueOf(num4);
BigDecimal bd4_3 = BigDecimal.valueOf(num4);
assertSame(bd4_1, bd4_2);
assertSame(bd4_2, bd4_3);
Long num42 = -42L;
BigDecimal bd42_1 = BigDecimal.valueOf(num42);
BigDecimal bd42_2 = BigDecimal.valueOf(num42);
BigDecimal bd42_3 = BigDecimal.valueOf(num42);
assertNotSame(bd42_1, bd42_2);
assertNotSame(bd42_1, bd42_3);
assertNotSame(bd42_2, bd42_3);
如我们所见,我们调用了BigDecimal.valueOf(num4)
三次。方法每次都返回相同的缓存对象。但是,当long
值不在0到10之间时,方法始终返回一个新的对象。
另一方面,每次调用构造函数时,BigDecimal
类都会为我们构建不同的对象:
Long num4 = 4L;
BigDecimal result1 = new BigDecimal(num4);
BigDecimal result2 = new BigDecimal(num4);
BigDecimal result3 = new BigDecimal(num4);
assertNotSame(result1, result2);
assertNotSame(result2, result3);
assertNotSame(result1, result3);
Long num42 = -42L;
BigDecimal bd42_1 = new BigDecimal(num42);
BigDecimal bd42_2 = new BigDecimal(num42);
BigDecimal bd42_3 = new BigDecimal(num42);
assertNotSame(bd42_1, bd42_2);
assertNotSame(bd42_1, bd42_3);
assertNotSame(bd42_2, bd42_3);
6. 总结
在这篇文章中,我们了解了将Long
值转换为BigDecimal
对象的两种方法。
在实践中,我们应该优先选择BigDecimal.valueOf()
,因为它可以在long
值在0到10之间时利用缓存的对象。
如往常一样,本文中展示的所有代码片段都可以在GitHub上找到。