TreeSet等于另一个TreeSet

时间:2019-02-08 12:14:21

标签: java collections treeset

如何确定两个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使用压缩程序或元素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或其他库中的其他哪个集合来保证元素的唯一性和排序,并且等于另一个集合中每个元素等于的使用。

3 个答案:

答案 0 :(得分:2)

JavaDoc for TreeSet明确地说了这句话。这不是阴谋。

  

请注意,集合维护的排序(无论是否显式   提供比较器)必须与equals 保持一致   正确实现Set接口。 (请参阅可比或比较器   才能精确定义与equals的一致性。)   因为Set接口是根据equals操作定义的,   ,但是TreeSet实例使用其实例执行所有元素比较   compareTo (或比较)方法,因此两个元素被视为相等   从集合的角度来看,此方法是相等的。的   集合的行为是明确定义的,即使其顺序不一致   等于它只是不服从套装的总合约   界面。

您的课程忽略了the advice of Comparable,您需要为此付费。

  

强烈建议,但并非严格要求   (x.compareTo(y)==0) == (x.equals(y))

答案 1 :(得分:2)

如果具有“已定义对象集”,则可以覆盖哈希码和equals方法,下面的方法将根据哈希码和equals方法进行比较。 您可以使用

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

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

答案 2 :(得分: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.
    }
}

我为什么要这样做?好吧,在我们的代码中,我们为使用Objects.equals(this.field_i, that.field_i)的Idea->中的其他对象生成了相等值。我们很懒惰地在代码中搜索位置,如果Objects.equals(this.field_i, that.field_i)是util类中的排序集,则替换field_i来检查集合是否相等。因此,使用支持排序但在eqauls中的每个元素上使用this.equals的集合更容易。

有人告诉我eqaulshashCodecompareTo必须一致。我同意eqaulshashCode必须保持一致。

例如。

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.
}

现在,如果您想保留一个射手并将kafka中的消息发送给其他微服务,您将拥有equals来检查谁是 Shooter 实体。