TreeSet等于另一个TreeSet

问题描述 投票:0回答:3

如何找出两个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或我可以使用的其他库的其他集合保证了唯一元素和排序,并且等于另一个集合用于每个元素等于。

java collections treeset
3个回答
2
投票

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))


2
投票

如果你有Set of Defined Object,那么你可以基于hashcode和equals方法覆盖hashcode和equals方法以及下面的方法比较。您可以使用

 org.apache.commons.collections
 SetUtils.isEqualSet(set1, set2);

要么

 org.apache.commons.collections
 CollectionUtils.isEqualCollection(a, b)

0
投票

这是一个对我有用的解决方案。

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

有些人告诉我,eqaulshashCodecompareTo必须保持一致。我同意eqaulshashCodemust是一致的。

例如。

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来检查谁是射手实体。

© www.soinside.com 2019 - 2024. All rights reserved.