BigDecimal,相信很多人都不陌生,很多人都知道它的用法。这是java.math包中提供的一种类型,可用于精确计算。很多人都知道,在金额表示、金额计算等场景中,不能使用double、float等类型,而应该使用精度支持更好的BigDecimal。因此,在很多支付、电子商务、金融等业务中,BigDecimal的使用非常频繁。而且不得不说这是一个非常好用的类,里面有很多方法,比如加减乘除等计算方法可以直接调用。代码除了需要用BigDecimal表示数字,进行数字运算外,还经常需要判断数字是否相等。这个关于BigDecimal等价判断的知识点在《阿里巴巴Java开发手册》的最新版本中也有说明:那么,为什么会有这样的要求呢?背后的想法是什么?其实我在之前的CodeReview中看到过如下低级错误:if(bigDecimal==bigDecimal1){//两个数相等}这种错误,相信聪明的读者一眼就能看出问题所在,因为BigDecimal是一个对象,所以不能用==来判断两个数的值是否相等。上面的问题在有了一些经验之后还是可以避免的,但是聪明的读者,看看下面这行代码,你觉得是不是有问题:if(bigDecimal.equals(bigDecimal1)){//两个数字是equal}可以很明确的告诉大家,上面的写法可能会得到和你预期的不一样的结果!我们先做个实验,运行如下代码:BigDecimalbigDecimal=newBigDecimal(1);BigDecimalbigDecimal1=newBigDecimal(1);System.out.println(bigDecimal.equals(bigDecimal1));BigDecimalbigDecimal2=newBigDecimal(1);BigDecimalbigDecimal3=newBigDecimal(1.0);System.out.println(bigDecimal2.equals(bigDecimal3));BigDecimalbigDecimal4=newBigDecimal("1");BigDecimalbigDecimal5=newBigDecimal("1.0");System.out.println(bigDecimal4.equals(bigDecimal5));以上代码,输出结果为:truetruefalseBigDecimal的equals原理通过上面的代码示例,我们发现在使用BigDecimal的equals方法比较1和1.0时,有时为真(使用int、double定义BigDecimal时),有的则为false(当使用String定义BigDecimal时)。那么,为什么会这样呢?我们先看BigDecimal的equals方法。在BigDecimal的JavaDoc中,其实已经解释了原因:ComparesthisBigDecimalwiththespecifiedObjectforequality.与compareTo不同,thismethodconsiderstwoBigDecimalobjectsequalonlyiftheyareequalinvalueandscale(thus2.0isnotequalto2.00whencomparedbythismethod)大概意思是equals方法和compareTo方法会比较两部分值,equals精度对应的代码(scale)如下:?所以,上面代码定义的两个BigDecimal对象(bigDecimal4和bigDecimal5)的精度是不同的,所以用equals比较的结果是false。尝试调试代码。在调试过程中,我们也可以看到bigDecimal4的精度为0,bigDecimal5的精度为1。精度不同。那么,为什么精度不同呢?为什么bigDecimal2和bigDecimal3精度相同(用int,double定义BigDecimal时),而bigDecimal4和bigDecimal5不一样(用String定义BigDecimal时)?为什么精度不同?这就涉及到BigDecimal的精度了。这个问题其实比较复杂。由于不是本文的重点,这里简单介绍一下。大家有兴趣的话,后面会单独说。首先,BigDecimal有以下四种构造方法:BigDecimal(int)BigDecimal(double)BigDecimal(long)BigDecimal(String)以上四种方法,创建的BigDecimal的精度不同。BigDecimal(long)和BigDecimal(int)首先最简单的就是BigDecimal(long)和BigDecimal(int),因为是整数,所以精度为0:publicBigDecimal(intval){this.intCompact=val;this.scale=0;this.intVal=null;}publicBigDecimal(longval){this.intCompact=val;this.intVal=(val==INFLATED)?INFLATED_BIGINT:null;this.scale=0;}BigDecimal(double)和BigDecimal(double),当我们使用newBigDecimal(0.1)创建一个BigDecimal时,创建的值并不完全等于0.1,而是0.1000000000000000055511151231257827021181583404541015625。这是因为doule本身仅代表一个近似值。那么,无论我们用newBigDecimal(0.1)还是newBigDecimal(0.10)来定义,它的近似值都是0.1000000000000000055511151231257827021181583404541015625,那么它的精度就是这个数的位数,也就是55。数字。对于newBigDecimal(1.0)这样的形式,由于他本质上是一个整数,所以他创建的数的精度为0。因此,由于BigDecimal(1.0)和BigDecimal(1.00)的精度相同,所以在使用equals时方法进行比较,结果为真。BigDecimal(string)和BigDecimal(double),当我们使用newBigDecimal("0.1")创建一个BigDecimal时,创建的值正好等于0.1。那么他的精度就是1,如果用newBigDecimal("0.10000"),创建出来的数是0.10000,精度是5。所以,由于BigDecimal("1.0")和BigDecimal("1.00")的精度不同,所以用equals方法比较时,结果为false。如何比较BigDecimal前面我们讲解了BigDecimal的equals方法,它不仅比较数字的值,还会比较它们的精度。因此,我们在使用equals方法判断两个数是否相等时,是极其严格的。那么,如果我们只是想判断两个BigDecimal的值是否相等,应该怎么判断呢?BigDecimal中提供了compareTo方法,只能比较两个数的值,两个数相等则返回0。BigDecimalbigDecimal4=newBigDecimal("1");BigDecimalbigDecimal5=newBigDecimal("1.0000");System.out.println(bigDecimal4.compareTo(bigDecimal5));以上代码,输出结果:0源码如下:总结BigDecimal是一个非常好用的表示高精度数字的类,它提供了很多丰富的方法。不过,他在使用equals方法的时候需要小心,因为他比较的时候不仅仅是比较两个数的值,还会比较它们的精度。只要这两个因素之一不相等,结果也为假,如果读者想比较两个BigDecimal值,可以使用compareTo方法。
