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上找到。