Bigdecimal类型如何比较值相等

Bigdecimal是一个对象,不是基本的数据类型,因此没有Bigdecimal数据类型比较方法这么一说。这里总结一下Bigdecimal对象如何比较值相等。

 

1、Bigdecimal类型不能直接使用 "=="

 

可以看到,由于是包装类型,因此建议使用equals 进行比较

但是使用equals进行比较就一定对吗?

 

2、BigDecimal类型使用equals比较中的坑

测试代码如下:

 1 public class BigDecimalTest {
 2     void test01(){
 3         BigDecimal num1 = BigDecimal.valueOf(0.00);
 4         System.out.println(num1.equals(0));     //false
 5         System.out.println(num1.equals("0"));   //false
 6     }
 7 
 8     void test02(){
 9         BigDecimal num1 = new BigDecimal("0.00");
10         System.out.println(num1.equals(0));     //false
11         System.out.println(num1.equals("0"));   //false
12     }
13 
14     void test03(){
15         BigDecimal a = new BigDecimal(0.00);
16         BigDecimal b = new BigDecimal(0);
17         System.out.println(a.equals(b));    //true         
18     }
19 
20     void test04(){
21         BigDecimal a = new BigDecimal("0.00");
22         BigDecimal b = new BigDecimal("0");
23         System.out.println(a.equals(b));    //false
24     }
25 
26     public static void main(String[] args) {
27         BigDecimalTest t = new BigDecimalTest();
28         System.out.println("test01():________________");
29         t.test01();
30         System.out.println("test02():________________");
31         t.test02();
32         System.out.println("test03():________________");
33         t.test03();
34         System.out.println("test04():________________");
35         t.test04();
36     }
37 }

 

我们可以看到,我们使用不同的方法构造的BigDecimal类型的数据,但是结果并不是相等的

传入字符串的构造器时等同于数据库查询出来的值

 

原因是什么呢?

我们来看一下传如String类型时的构造器:

1 public BigDecimal(String val) {
2     this(val.toCharArray(), 0, val.length());
3 }

该构造器的注释:

 

可以看出,“0”传入构造器得到的是0且没有小数位,“0.00”传入构造器得到的是0.00,含有2位小数

再看看equals方法:

 1     public boolean equals(Object x) {
 2         //比较对象是否是BigDecimal的数据类型,如果不是直接返回false
 3         if (!(x instanceof BigDecimal))
 4             return false;
 5         BigDecimal xDec = (BigDecimal) x;
 6         if (x == this)
 7             return true;
 8         //比较BigDecimalde scale值是否相等
 9         /* scale 是BigDecimal 的标度。如果为零或正数,则标度是小数点后的位数。
10          如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂。例如,-3 标度是指非标度值乘以 1000。*/
11         if (scale != xDec.scale)
12             return false;
13         long s = this.intCompact;
14         long xs = xDec.intCompact;
15         // 返回给定的xDec.intVal的compact 值,如果太大,则返回INFLATED。
16         // 返回给定的this.intVal的compact 值,如果太大,则返回INFLATED。
17         if (s != INFLATED) {
18             if (xs == INFLATED)
19                 xs = compactValFor(xDec.intVal);
20             return xs == s;
21         } else if (xs != INFLATED)
22             return xs == compactValFor(this.intVal);
23 
24         return this.inflated().equals(xDec.inflated());
25     }

该方法的注释为:

 

可以清晰看到equals方法比较了小数位数 -----> if (scale != xDec.scale) return false; 

到这里可以理解上面test04()比较结果为什么是false了

 

而使用new Decimal(double val),是将双精度转换为BigDecimal,BigDecimal是双精度二进制浮点值的精确十进制表示形式。返回的BigDecimal的小数位数是最小的值,因此(10scale×val)是一个整数。

官方注释说这个构造函数的结果可能有些不可预测。不建议使用

 

3、BigDecimal类型应该使用compareTo()方法进行比较

compareTo()方法:
* 将此 BigDecimal 与指定的 BigDecimal 比较。
*值相等但具有不同标度的两个 BigDecimal 对象(如,2.0 和 2.00)被认为是相等的。
* 小于、等于或大于 时,返回 -1、0 或 1

public class BigDecimalTest {
    void test05(){
        BigDecimal num1 = new BigDecimal("0");
        BigDecimal num2 = new BigDecimal("0.00");
        System.out.println(num2.compareTo(num1)); // 0
    }

    public static void main(String[] args) {
        BigDecimalTest t = new BigDecimalTest();
        t.test05();
    }
}

对于compareTo() 方法:

 1     public int compareTo(BigDecimal val) {
 2         // Quick path for equal scale and non-inflated case.
 3         if (scale == val.scale) {
 4             long xs = intCompact;
 5             long ys = val.intCompact;
 6             if (xs != INFLATED && ys != INFLATED)
 7                 return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
 8         }
 9         int xsign = this.signum();
10         int ysign = val.signum();
11         if (xsign != ysign)
12             return (xsign > ysign) ? 1 : -1;
13         if (xsign == 0)
14             return 0;
15         int cmp = compareMagnitude(val);
16         return (xsign > 0) ? cmp : -cmp;
17     }

可以看到,分了2种情况,一种是含有小数位相同,另一种时不相同的情况。所以不管2个数的小数位是否相同,都会进行值的比较。

posted @ 2022-02-15 11:03  r1-12king  阅读(4226)  评论(0编辑  收藏  举报