从集合中获取元素

2022-08-31 04:37:09

为什么不提供一个操作来获取等于另一个元素的元素?Set

Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo);   // get the Foo element from the Set that equals foo

我可以问是否包含一个等于的元素,那么为什么我不能得到那个元素?:(Setbar

为了澄清,该方法被覆盖,但它只检查其中一个字段,而不是全部字段。因此,两个被视为相等的对象实际上可以具有不同的值,这就是为什么我不能只使用.equalsFoofoo


答案 1

为了回答确切的问题“为什么不提供一个操作来获得一个等于另一个元素的元素?”,答案是:因为集合框架的设计者不是很有远见。他们没有预料到你非常合法的用例,天真地试图“模拟数学集合抽象”(来自javadoc),只是忘记了添加有用的方法。Setget()

现在来看看隐含的问题“那么你如何得到元素”:我认为最好的解决方案是使用 a 而不是 a ,将元素映射到自身。这样,您就可以有效地从“set”中检索元素,因为 的 get() 方法将使用有效的哈希表或树算法查找该元素。如果需要,可以编写自己的实现,该实现提供了附加方法,封装了 .Map<E,E>Set<E>MapSetget()Map

在我看来,以下答案是坏的或错的:

“你不需要得到这个元素,因为你已经有一个相等的对象”:断言是错误的,正如你在问题中已经展示的那样。两个相等的对象仍然可以具有不同的状态,这与对象相等性无关。目标是访问 包含在 中的元素的此状态,而不是用作“查询”的对象的状态。Set

“你别无选择,只能使用迭代器”:这是对一个集合的线性搜索,对于大型集合来说效率完全低下(具有讽刺意味的是,内部组织为可以有效查询的哈希映射或树)。别这样!通过使用这种方法,我在现实生活中看到了严重的性能问题。在我看来,缺少的方法的可怕之处不在于解决它有点麻烦,而是大多数程序员会使用线性搜索方法而不考虑其含义。Setget()


答案 2

如果元素相等,则获取该元素是没有意义的。A 更适合此用例。Map


如果您仍然想找到该元素,则除了使用迭代器之外别无选择:

public static void main(String[] args) {

    Set<Foo> set = new HashSet<Foo>();
    set.add(new Foo("Hello"));

    for (Iterator<Foo> it = set.iterator(); it.hasNext(); ) {
        Foo f = it.next();
        if (f.equals(new Foo("Hello")))
            System.out.println("foo found");
    }
}

static class Foo {
    String string;
    Foo(String string) {
        this.string = string;
    }
    @Override
    public int hashCode() { 
        return string.hashCode(); 
    }
    @Override
    public boolean equals(Object obj) {
        return string.equals(((Foo) obj).string);
    }
}

推荐