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個數的小數位是否相同,都會進行值的比較。