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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何更改Java Set的retainall方法以使用equals方法而不是==运算符?相关的知识,希望对你有一定的参考价值。

我试图测试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方法相比。

答案

您的问题中的陈述:

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

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

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

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

你可以像这样使用它:

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

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

另一答案

实际上保留所有使用包含本身使用等于,至少标准版本。也许你实际上使用的是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的代码)或谷歌它(如HashSet.retainAll代码源)你会发现类似的东西:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/HashSet.java

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

另一答案

如果你检查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()检查,这是你想要的。

以上是关于如何更改Java Set的retainall方法以使用equals方法而不是==运算符?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA怎么取多个List集合的交集?

瞬间教你学会使用java中list的retainAll方法

瞬间教你学会使用java中list的retainAll方法

TreeMap中的keySet()方法的功能

请问java有工具类取两个list的并集吗?

set接口