gpt4 book ai didi

java - AbstractSet.removeAll() 方法无法正常工作

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:15:00 25 4
gpt4 key购买 nike

下面显示的代码确实输出:

[b]

[a, b]

但是我希望它在输出中打印两行相同的行。

import java.util.*;

public class Test{
static void test(String... abc) {
Set<String> s = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
s.addAll(Arrays.asList("a", "b"));
s.removeAll(Arrays.asList(abc));
System.out.println(s);
}

public static void main(String[] args) {
test("A");
test("A", "C");
}
}

规范明确指出 removeAll

"Removes all this collection's elements that are also contained in the specified collection."

所以根据我的理解,当前的行为是不可预测的。请帮助我理解这一点

最佳答案

您只阅读了部分文档。您忘记了 TreeSet 中的一个重要段落:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

现在 removeAll 实现来自 AbstractSet 并利用 equals 方法。根据您的代码,您将得到 "a".equals("A") 不是 true,因此即使您提供了一个管理比较器,元素也不被视为相等它们在 TreeSet 本身中使用时。如果您尝试使用包装器,那么问题就会消失:

import java.util.*;
import java.lang.*;

class Test
{
static class StringWrapper implements Comparable<StringWrapper>
{
public final String string;

public StringWrapper(String string)
{
this.string = string;
}

@Override public boolean equals(Object o)
{
return o instanceof StringWrapper &&
((StringWrapper)o).string.compareToIgnoreCase(string) == 0;
}

@Override public int compareTo(StringWrapper other) {
return string.compareToIgnoreCase(other.string);
}

@Override public String toString() { return string; }
}

static void test(StringWrapper... abc)
{
Set<StringWrapper> s = new TreeSet<>();
s.addAll(Arrays.asList(new StringWrapper("a"), new StringWrapper("b")));
s.removeAll(Arrays.asList(abc));
System.out.println(s);
}

public static void main(String[] args)
{
test(new StringWrapper("A"));
test(new StringWrapper("A"), new StringWrapper("C"));
}
}

这是因为您现在在对象的 equalscompareTo 之间提供了一致的实现,因此您永远不会在如何将对象添加到有序集合和集合的所有抽象行为如何使用它们。

这在一般情况下是正确的,Java 代码的一种三规则:如果你实现 compareToequalshashCode 你应该始终实现所有这些以避免标准集合出现问题(即使 hashCode 不太重要,除非您在任何散列集合中使用这些对象)。这在 Java 文档中多次指定。

关于java - AbstractSet.removeAll() 方法无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43121742/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com