来自 the Javadoc for BigDecimal
:
Note: care should be exercised if
BigDecimal
objects are used as keys in aSortedMap
or elements in aSortedSet
sinceBigDecimal
's natural ordering is inconsistent with equals.
例如,如果您创建一个 HashSet
并将 new BigDecimal("1.0")
和 new BigDecimal("1.00")
添加到它,该集合将包含两个元素(因为值具有不同的比例,因此根据 equals
和 hashCode
不相等),但如果你做同样的事情TreeSet
,该集合将只包含一个元素,因为当您使用 compareTo
时,值比较相等。
这种不一致背后有什么具体原因吗?
最佳答案
来自 OpenJDK implementation BigDecimal:
/**
* 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());
}
更多的实现:
* <p>Since the same numerical value can have different
* representations (with different scales), the rules of arithmetic
* and rounding must specify both the numerical result and the scale
* used in the result's representation.
这就是为什么 equals
的实现会考虑 scale
的原因。以字符串为参数的构造函数实现如下:
public BigDecimal(String val) {
this(val.toCharArray(), 0, val.length());
}
第三个参数将用于 scale
(在另一个构造函数中),这就是字符串 1.0
和 1.00
将创建不同的原因BigDecimals(具有不同的比例)。
来自 Effective Java 约书亚·布洛赫:
The final paragraph of the compareTo contract, which is a strong suggestion rather than a true provision, simply states that the equality test imposed by the compareTo method should generally return the same results as the equals method. If this provision is obeyed, the ordering imposed by the compareTo method is said to be consistent with equals. If it’s violated, the ordering is said to be inconsistent with equals. A class whose compareTo method imposes an order that is inconsistent with equals will still work, but sorted collections containing elements of the class may not obey the general contract of the appropriate collection interfaces (Collection, Set, or Map). This is because the general contracts for these interfaces are defined in terms of the equals method, but sorted collections use the equality test imposed by compareTo in place of equals. It is not a catastrophe if this happens, but it’s something to be aware of.
关于java - 为什么 BigDecimal 自然排序与 equals 不一致?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19818537/