您的位置:首页 > 编程语言 > Java开发

Java 中 BigDecimal 的 equals() 与 compareTo() 的区别

2018-01-22 15:16 183 查看
这两天在设计金额表字段类型的时候,在 double 和 decimal 之间犹豫了半天,讲道理应该是用decimal的,但是以前的人的表设计是用double的,最终我还是坚持真理用了decimal,虽然都是浮点数,但是用 int(单位:分)再转换为 double 来显示都比直接用 double 靠谱,double 可能会发生一些精度不准的现象,而 decimal 是对象,用方法操作,不直接用运算符运算,在金额方面是很安全的。

【jre7】:equals():

可以看到BigDecimal的euquals方法是先判断要比较的数据类型,如果对象类型一致前提下同时判断精确度(scale)和值(BigInteger的equals方法)是否一致。

/**
* Compares this {@code BigDecimal} with the specified
* {@code Object} for equality.  Unlike {@link
* #compareTo(BigDecimal) compareTo}, this method considers two
* {@code 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).
*
* @param  x {@code Object} to which this {@code BigDecimal} is
*         to be compared.
* @return {@code true} if and only if the specified {@code Object} is a
*         {@code BigDecimal} whose value and scale are equal to this
*         {@code BigDecimal}'s.
* @see    #compareTo(java.math.BigDecimal)
* @see    #hashCode
*/
@Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);

return this.inflate().equals(xDec.inflate());
}


【jre7】:compareTo()

可以看到这个方法里面有个matchScale的处理,意思是把精确度低的那个对象转换为高精确度,然后再进行比较(同样是BigInteger的compareTo方法)。

/**
* Compares this {@code BigDecimal} with the specified
* {@code BigDecimal}.  Two {@code BigDecimal} objects that are
* equal in value but have a different scale (like 2.0 and 2.00)
* are considered equal by this method.  This method is provided
* in preference to individual methods for each of the six boolean
* comparison operators ({@literal <}, ==,
* {@literal >}, {@literal >=}, !=, {@literal <=}).  The
* suggested idiom for performing these comparisons is:
* {@code (x.compareTo(y)} <<i>op</i>> {@code 0)}, where
* <<i>op</i>> is one of the six comparison operators.
*
* @param  val {@code BigDecimal} to which this {@code BigDecimal} is
*         to be compared.
* @return -1, 0, or 1 as this {@code BigDecimal} is numerically
*          less than, equal to, or greater than {@code val}.
*/
public int compareTo(BigDecimal val) {
// Quick path for equal scale and non-inflated case.
if (scale == val.scale) {
long xs = intCompact;
long ys = val.intCompact;
if (xs != INFLATED && ys != INFLATED)
return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
}
int xsign = this.signum();
int ysign = val.signum();
if (xsign != ysign)
return (xsign > ysign) ? 1 : -1;
if (xsign == 0)
return 0;
int cmp = compareMagnitude(val);
return (xsign > 0) ? cmp : -cmp;
}

matchScale():

/**
* Match the scales of two {@code BigDecimal}s to align their
* least significant digits.
*
* <p>If the scales of val[0] and val[1] differ, rescale
* (non-destructively) the lower-scaled {@code BigDecimal} so
* they match.  That is, the lower-scaled reference will be
* replaced by a reference to a new object with the same scale as
* the other {@code BigDecimal}.
*
* @param  val array of two elements referring to the two
*         {@code BigDecimal}s to be aligned.
*/
private static void matchScale(BigDecimal[] val) {
if (val[0].scale == val[1].scale) {
return;
} else if (val[0].scale < val[1].scale) {
val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
} else if (val[1].scale < val[0].scale) {
val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
}
}


做个简单测试:

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的大小比较,用equals方法的话会不仅会比较值的大小,还会比较两个对象的精确度,而compareTo方法则不会比较精确度,只比较数值的大小
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: