如何找出两个TreeSet
对象是否相等?我用open-jdk-10。
ModifiebleObject
class ModifiebleObject implements Comparable<ModifiebleObject>{
Integer number;
String text;
@Override
public int compareTo(final ModifiebleObject o) {
return this.number - o.number;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof ModifiebleObject)) return false;
final ModifiebleObject that = (ModifiebleObject) o;
return Objects.equals(number, that.number) &&
Objects.equals(text, that.text);
}
@Override
public int hashCode() {
return Objects.hash(number, text);
}
}
SomeCode
SortedSet<ModifiebleObject> tree1 = prepare();
SortedSet<ModifiebleObject> tree2 = prepare(); //Returns cloned elements, so object references in tree1 and tree2 are different.
// ModifiebleObject implements Comparable<ModifiebleObject>
// compareTo does not use all the fields, just some of them.
//setSomeValueOutsideOfComparable sets value of the field, which is not used by compareTo
tree2.first().setSomeValueOutsideOfComparable("newValue");
boolean tree1EqualsTree2 = tree1.equals(tree2); //Returns true
因为
TreeSet调用AbstractSet.containsAll
- > TreeSet.contains
- > TreeMap.containsKey
- > TreeMap.getEntry != null
TreeMap.getEntry
使用compactor或elements compareTo(元素实现Comparable)。
有趣,但JavaDoc谎言!
java.utilTreeSet
/**
* Returns {@code true} if this set contains the specified element.
* More formally, returns {@code true} if and only if this set
* contains an element {@code e} such that
* {@code Objects.equals(o, e)}.
*
* @param o object to be checked for containment in this set
* @return {@code true} if this set contains the specified element
* @throws ClassCastException if the specified object cannot be compared
* with the elements currently in the set
* @throws NullPointerException if the specified element is null
* and this set uses natural ordering, or its comparator
* does not permit null elements
*/
public boolean contains(Object o) {
return m.containsKey(o);
}
更正式地,当且仅当此集合包含{@code e}元素{@code Objects.equals(o,e)}时才返回{@code true}。
但实际上它使用compareTo
。
来自jdk或我可以使用的其他库的其他集合保证了唯一元素和排序,并且等于另一个集合用于每个元素等于。
JavaDoc for TreeSet
明确地说明了这一点。这不是一些阴谋。
请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,通过这种方法被认为相等的元素是相等的。集合的行为即使其排序与equals不一致也是明确定义的;它只是不遵守Set接口的一般合同。
你的班级忽略了the advice of Comparable
并且你付出了代价。
强烈建议,但不严格要求
(x.compareTo(y)==0) == (x.equals(y))
如果你有Set of Defined Object,那么你可以基于hashcode和equals方法覆盖hashcode和equals方法以及下面的方法比较。您可以使用
org.apache.commons.collections
SetUtils.isEqualSet(set1, set2);
要么
org.apache.commons.collections
CollectionUtils.isEqualCollection(a, b)
这是一个对我有用的解决方案。
class TreeSetWithEquals extends TreeSet {
//Constructors which I will use
//
// I consider two sets equal if they have equal elements in the same order!
@Override
public boolean equals(Object o) {
//Check if Object not null, not the same reference as this, and
// it is instance of Set
//And their sizes are equal
//Iterate through boths sets and apply equals for each method.
}
}
我为什么要这样做?好吧,在我们的代码中,我们为Idea中的其他对象生成了等于 - >使用Objects.equals(this.field_i, that.field_i)
。如果Objects.equals(this.field_i, that.field_i)
是一个有组合的集合到检查集合的相等性,我们懒于搜索代码中的地方并替换field_i
。因此,使用支持排序的集合更容易,但对eqauls
中的每个元素使用this.equals
。
有些人告诉我,eqauls
,hashCode
,compareTo
必须保持一致。我同意eqauls
,hashCode
must是一致的。
例如。
enum WeaponType {
KNIFE,
HAND_GUN,
TWO_HANDED_GUN,
GRANADES, //To allow flash, smoke and fragmentation granades
DEFUSE_KIT
}
class Shooter {
// make sure we can have different weapons,
// but only one of type is allowed.
// Our tree set with such comparator will guarantee this requirement.
private SortedSet<Weapon> weapons = buyWeapons(andUseWeaponTypeComparator);
为此,我将定义一个WeaponComparator
Comparator<Weapon> WEAPON_COMPARATOR = Compareator
.comparing(Weapon::getType, Comparator.naturalOrder()) //enum uses its element order.
}
现在,如果你想坚持射击游戏并将卡夫卡发送给其他微服务,你将拥有equals
来检查谁是射手实体。