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个数的小数位是否相同,都会进行值的比较。