1. 程式人生 > >java中BigDecimal的equals與compareTo的區別

java中BigDecimal的equals與compareTo的區別

這兩天在處理支付金額校驗的時候出現了點問題,有個金額比較我用了BigDecimal的equals方法來比較兩個金額是否相等,結果導致金額比較出現錯誤(比如3.0與3.00的比較等)。 【注:以下所講都是以sun jdk 1.4.2版本為例,其他版本實現未必一致,請忽略】 首先看一下BigDecimal的equals方法:
public boolean equals(Object x){
	if (!(x instanceof BigDecimal))
	    return false;
	BigDecimal xDec = (BigDecimal) x;

	return scale == xDec.scale && intVal.equals(xDec.intVal);
    }

可以看到BigDecimal的euquals方法是先判斷要比較的資料型別,如果物件型別一致前提下同時判斷精確度(scale)和值(BigInteger的equals方法)是否一致。
其實javadoc裡面就已經寫的很明白:“Compares this BigDecimal with the specified Object for equality. Unlike compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by this method).”只是自己沒有去注意罷了! 再看一下compareTo方法:  
public int compareTo(BigDecimal val){
	/* Optimization: would run fine without the next three lines */
	int sigDiff = signum() - val.signum();
	if (sigDiff != 0)
	    return (sigDiff > 0 ? 1 : -1);

	/* If signs match, scale and compare intVals */
	BigDecimal arg[] = new BigDecimal[2];
	arg[0] = this;	arg[1] = val;
	matchScale(arg);
	return arg[0].intVal.compareTo(arg[1].intVal);
    }
可以看到這個方法裡面有個matchScale的處理,意思是把精確度低的那個物件轉換為高精確度,然後再進行比較(同樣是BigInteger的compareTo方法),matchScale的實現如下:
private static void matchScale(BigDecimal[] val) {
	if (val[0].scale < val[1].scale)
	    val[0] = val[0].setScale(val[1].scale);
	else if (val[1].scale < val[0].scale)
	    val[1] = val[1].setScale(val[0].scale);
    }

做個簡單測試:       System.out.println(new BigDecimal("1.2").equals(new BigDecimal("1.20")));  //輸出false       System.out.println(new BigDecimal("1.2").compareTo(new BigDecimal("1.20")) == 0); //輸出true     另外注意到我上面BigDecimal的構造方法裡面傳入的都是字串,如果傳入的是數字型別的話會有什麼結果,大家可以自己測試一下,然後分析一下原因:
System.out.println(new BigDecimal("1.2").equals(new BigDecimal("1.20")));  //輸出false
System.out.println(new BigDecimal("1.2").compareTo(new BigDecimal("1.20")) == 0); //輸出true
        
System.out.println(new BigDecimal(1.2).equals(new BigDecimal("1.20"))); //輸出是?
System.out.println(new BigDecimal(1.2).compareTo(new BigDecimal("1.20")) == 0); //輸出是?
   
System.out.println(new BigDecimal(1.2).equals(new BigDecimal(1.20))); //輸出是?
System.out.println(new BigDecimal(1.2).compareTo(new BigDecimal(1.20)) == 0);//輸出是?
最後結論是:對於BigDecimal的大小比較,用equals方法的話會不僅會比較值的大小,還會比較兩個物件的精確度,而compareTo方法則不會比較精確度,只比較數值的大小。 最後鄙視一下自己,用了這麼多年的Java語言,連基本的常識都沒搞清楚!