为什么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

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

为了澄清,equals方法被重写,但它只检查其中一个字段,而不是所有字段。两个相等的Foo对象可以有不同的值,这就是为什么我不能只用Foo。


当前回答

哈希码的契约清楚地表明:

如果根据Object方法,两个对象是相等的,那么在这两个对象上调用hashCode方法必须产生相同的整数结果。

所以你的假设是

为了澄清,equals方法被重写,但它只检查其中之一 田地,不是全部。所以两个相等的Foo对象可以 有不同的值,这就是为什么我不能只使用foo。”

是错误的,你违反了合同。如果我们看Set接口的"contains"方法,我们有:

boolean contains(Object o); 如果此集合包含指定的元素,则返回true。更多的 形式上,当且仅当此集合包含元素时返回true "e"使得o==null ?E ==null: o. = (E)

为了实现您想要的效果,您可以使用Map,在其中定义键并使用定义对象如何彼此不同或相等的键存储元素。

其他回答

Why:

Set似乎在提供比较手段方面发挥了有用的作用。它被设计为不存储重复的元素。

由于这种意图/设计,如果要获得()对存储对象的引用,然后更改它,则Set的设计意图可能会受到阻碍,并可能导致意想不到的行为。

来自JavaDocs

如果使用可变对象作为set元素,必须非常小心。当对象是集合中的元素时,如果对象的值以影响相等比较的方式更改,则不指定集合的行为。

How:

现在已经引入了流,我们可以做以下事情

mySet.stream()
.filter(object -> object.property.equals(myProperty))
.findFirst().get();

因为Set的任何特定实现都可能是随机访问,也可能不是。

You can always get an iterator and step through the Set, using the iterators' next() method to return the result you want once you find the equal element. This works regardless of the implementation. If the implementation is NOT random access (picture a linked-list backed Set), a get(E element) method in the interface would be deceptive, since it would have to iterate the collection to find the element to return, and a get(E element) would seem to imply this would be necessary, that the Set could jump directly to the element to get.

当然,Contains()可能需要做同样的事情,也可能不需要,这取决于实现,但名称似乎不会导致同样的误解。

如果你有一个相等的对象,为什么你需要集合中的一个?如果它仅与键“相等”,则Map将是更好的选择。

不管怎样,下面的方法就可以了:

Foo getEqual(Foo sample, Set<Foo> all) {
  for (Foo one : all) {
    if (one.equals(sample)) {
      return one;
    }
  } 
  return null;
}

在Java 8中,这可以变成一行代码:

return all.stream().filter(sample::equals).findAny().orElse(null);

如果你想要HashSet中的第n个元素,你可以使用下面的解决方案, 这里我在HashSet中添加了ModelClass对象。

ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
    m1 = (ModelClass) itr.next();
    if(nth == index) {
        System.out.println(m1);
        break;
    }
}

将set转换为list,然后使用list的get方法

Set<Foo> set = ...;
List<Foo> list = new ArrayList<Foo>(set);
Foo obj = list.get(0);