今天在工作过程中喷到的问题,与BigDecimal这个类型相关。
需求上是前端传两个参数,税前金额和税后金额,后端要校验关系是否正确,参数的接收使用BigDecimal类型。
两个参数如下所示
BigDecimal amount = request.getAmount().divide(new BigDecimal(1.071),2,BigDecimal.ROUND_DOWN);
BigDecimal payAmount request.getPayAmount();
return amount.equals(payAmount);
然后发现有些情况下明明应该是相等的时候返回false。
我们用一下的代码来测试
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1.00");
BigDecimal b = new BigDecimal("1");
System.out.println(b.equals(a));
System.out.println(b.compareTo(a));
}
执行结果如下
一个出乎意料的结果。
既然如此,我们先来仔细看一下BigDecimal的底层结构。
BIgDecimal类的继承了Number类并实现了Comparable接口用于比较。
BigDecimal对象由一下几个属性构成
/**
* 初始化时若传入的字符串长度超过18,则将结果去掉小数点后存储于此
* 否则为null
*/
private final BigInteger intVal;
/**
*小数精度,即小数点后位数
*/
private final int scale; // Note: this may have any value, so
// calculations must be done in longs
/**
* 总精度,即总数字位数
*/
private transient int precision;
/**
* 字符串备份
*/
private transient String stringCache;
/**
* 缩放为整数的结果,即有效数字,如果超出Long型的限制则值为-9223372036854775808
*/
private final transient long intCompact;
我们以"14.23"来构造一个BigDecimal对象,那么它的属性如下
我们以"61232343243432432413123.030"来构造一个BigDecimal对象,那么它的属性如下
那么我们来看文章开头出现的两个对象
new BigDecimal(“1.00”);
new BigDecimal(“1”);
可以看到两个对象的底层结构确实是不同的。
接下来我们看BigDecimal类的eq