为什么java.util.Set不包含值getter?有其他选择吗?

为什么java.util.Set不包含值getter?有其他选择吗?,java,collections,Java,Collections,由于集合项仅通过属性子集(hashCode()+equals())进行区分,因此有时需要对集合中包含的原始对象进行操作,这在java.util.set中是不可能的。我提出的唯一选择是:Map——这不是一个非常简洁的解决方案 集合框架中还有其他替代方案吗?要求是:O(1)基于hashCode()+equals()结果获取时间和无重复项。不在java.util.Collections本身中,但使用,您可以使用从给定的迭代器中检索任何元素 通常我不会提倡外部库,但考虑到番石榴的强大和实用性,我认为它没

由于集合项仅通过属性子集(
hashCode()
+
equals()
)进行区分,因此有时需要对集合中包含的原始对象进行操作,这在
java.util.set
中是不可能的。我提出的唯一选择是:
Map
——这不是一个非常简洁的解决方案


集合框架中还有其他替代方案吗?要求是:O(1)基于
hashCode()+equals()
结果获取时间和无重复项。

不在
java.util.Collections
本身中,但使用,您可以使用从给定的
迭代器中检索任何元素

通常我不会提倡外部库,但考虑到番石榴的强大和实用性,我认为它没有问题

或者,您可以使用自己的实现来迭代集合



另外,我在这里发现了一个非常有趣的解释这种行为的方法。

一个
集合
不能包含两个对象
o1
o2
,这样
o1.equals(o2
)(在这个标准中没有使用
hashCode


HashSet
使用hashmap高效地存储其对象,因此最终hashmap正是基于
hashCode()+equals()
的操作所需要的

如果你想重用它,我就编写了这样一个类。包含一个类
org.eclipse.recommenders.jayes.util.sharing.CanonicalSet
,该类允许基于几乎任何等价关系进行检索,这些等价关系可以在
hashCode()
equals()
实现中进行编码。我用它来构建数组等价类。您可以查看那些
CanonicalSet
的实现,它们在同一个包中


哦,但是是的,它也只是基于一个
映射
,所以没有什么神奇的地方。

基于HashMap的HashSet的代码非常简单:如果你看看它在JDK中的实现方式,实际的代码行非常少(忽略构造函数和序列化代码)

这样做的方法是使用附加的
get()
方法实现您自己版本的HashSet

public E get(Object o) {
   return map.get(o);
}
你可以从


它装饰
java.util.List
以确保不存在重复项,就像
java.util.Set

是的,不能共享相等的对象有点痛苦。Set API的问题在于缺少特定的addAndGet:

AddOnceSet<String> set = new AddOnceSet<>();
String s = in.readLine();
s = set.addOnce(s); // The new s is equal, and identical to the first added one.

s = set.getOnce(s);
如果一个以上的O(1)操作没有问题,您可以使用一对方法
set.remove(Object)
set.add(Object)
模拟缺席方法
get(Object)
。否则,我将使用您提到的
Map
,或者使用简单的包装类和底层Map


EDIT:之所以
Set
不包含
get(Object)
,是因为您不需要返回您知道的对象。您只需检查对象是否包含在集合中。

您在寻找吗?啊,所以您想要集合中的原始对象。最简单的方法就是你的地图解决方案。“这不是很方便的原因吗?”Marcin不,这就是你需要HashMap的原因。这是标准API中另一个基于哈希的集合。这是最省力的解决方案。这不是一个非常漂亮的解决方案,但您没有非常漂亮的要求:|@dhrubajyotigogi尝试从
HashSet
提取原始对象。这就是我想做的。映射是正确的解决方案。但它不再是O(1)。这不是他想要的:他想从一个集合中检索一个对象,该集合在恒定时间内
等于另一个对象。@arshajii我理解,但是Set接口不提供用于检索对象及其属性的get方法,因为这不是Set的意图。他要求通过使用hashcode和equals有效区分对象,这正是Hash映射的目的。所以你是说他应该使用
映射,正如他已经尝试过的那样?这实际上取决于他对原始对象的定义。它是指创建的同一实例(内存方面)还是指具有完全相同属性的对象。对于后者,他可以安全地使用Hashmap。我真的想知道,如果是这样的话,同样的例子需要什么。
private Map<T, T> sharedThings = new HashMap<>().

public T shareThing(T s) {
    String t = sharedThings.get(s);
    if (t == null) {
        t = s;
        sharedStrings.put(t, t);
    }
    return t;
}

...

public void setT(T t) {
    this.t = sharedThing(t);
}