如何更改Java Set的retainall方法以使用equals方法而不是==运算符?

时间:2018-01-28 16:24:08

标签: java string set equality set-intersection

我正在尝试测试两个HashSets Strings是否包含相同的Strings。 Java集的retainAll()方法(据我所知,它实现了Collection接口)是检查两个集合的交集的好方法。但是,此方法似乎使用==样式检查是否相等,以检查它们是否是对同一内存对象的引用,而不是使用String的equals()方法来检查内容是否相同。有没有办法获得像retainAll这样的工作但使用equals()方法?

我正在尝试编写代码来检查String是否包含来自某个其他String的特定长度的子字符串。我的策略是创建包含该长度的所有子串的每个String的HashSet,然后检查Sets是否包含共同的字符串。

我目前的解决方案是创建我自己的静态方法,该方法执行我想要retainAll方法的操作。

static boolean containsEqualElement(Set SetOne, Set SetTwo) {
    Iterator it = SetOne.iterator();
    while (it.hasNext()) {
        Object thisComp = it.next();
        Iterator it2 = SetTwo.iterator();
        while (it2.hasNext()) {
            if (it2.next().equals(thisComp)) {
                return true;
            }
        }
    }
    return false;
}

我不确定此方法的效率与retainAll方法的比较。

3 个答案:

答案 0 :(得分:2)

您的问题中的陈述:

  

但是,这个方法似乎使用==样式检查来测试是否它们是对同一个内存对象的引用,而不是使用String的equals()方法来检查内容是否相同

错了。 retainAll确实使用contains,后者又使用equals

我不完全理解您的用例,但我认为您可能会发现Collections.disjoint方法比retainAll更有用。来自文档:

  

如果两个指定的集合没有共同的元素,则返回true

您可以像这样使用它:

if (!Collections.disjoint(setOne, setTwo)) {
    // sets have at least one element in common
}

我建议您使用此方法,因为retainAll修改了调用它的集合。实际上,它会删除此集合中未包含在参数集合中的所有元素。从你的代码来看,你似乎不想要这种行为。

答案 1 :(得分:0)

实际上,保留所有使用包含本身使用等于,至少是标准版本。也许你实际上使用的是IdentityHashMap,它确实会使用内存引用来实现相等,但这可能是因为你要求它。

public boolean  [More ...] retainAll(Collection<?> c) {
        boolean modified = false;
        Iterator<E> e = iterator();
        while (e.hasNext()) {
            if (!c.contains(e.next())) {
                e.remove();
                modified = true;
            }
        }
        return modified;
    }

     public boolean  [More ...] contains(Object o) {
         Iterator<E> e = iterator();
        if (o==null) {
            while (e.hasNext())
                if (e.next()==null)
                    return true;
        } else 
            while (e.hasNext()
                if (o.equals(e.next()))
                    return true;
        }
        return false;
    }

下次,请考虑使用调试器进行双重检查(甚至是来自JDK的代码)或google它(如HashSet.retainAll代码源),您会发现类似的内容:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/HashSet.java

这就是我回答你的问题所做的。

答案 2 :(得分:0)

如果您选中OpenJDK9 source code,则可以看到retainAll()使用AbstractCollection.contains(Object o)

public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    boolean modified = false;
    Iterator<E> it = iterator();
    while (it.hasNext()) {
        if (!c.contains(it.next())) {
            it.remove();
            modified = true;
        }
    }
    return modified;
}

contains()的文档说:

  

如果此collection包含指定的元素,则返回true。更正式地,当且仅当此集合包含至少一个元素e时才返回true(o == null?e == null:o.equals(e))。

因此retainAll()基于equals()检查,这就是你想要的。