我相信有一个很好的理由,但有人能解释一下为什么java.util.Set接口缺少get(int Index),或任何类似的get()方法吗?

集合似乎很适合把东西放进去,但我找不到一种优雅的方法来从中检索单个项目。

如果我知道我想要的第一项,我可以使用set.iterator().next(),但否则,似乎我必须强制转换到一个数组来检索特定索引的项?

从集合中检索数据的适当方法是什么?(与使用迭代器不同)

我相信它被排除在API之外的事实意味着有一个很好的理由不这样做——有人能启发我吗?

编辑: 这里有一些非常棒的回答,还有一些说“更多的背景”。具体的场景是一个dbUnit测试,在这个测试中,我可以合理地断言从查询返回的集合只有1个项,并且我正在尝试访问该项。

然而,这个问题在没有场景的情况下更有效,因为它仍然更集中:

set和list的区别是什么?

感谢大家的精彩回答。


当前回答

Set是一个接口,它的一些实现类是HashSet、TreeSet和LinkedHashSet。它在底层使用HashMap来存储值。因为HashMap不保留顺序,所以不可能通过索引获取值。

你现在肯定在想Set是如何使用HashMap的,因为HashMap存储了一个键和值对,而Set没有。有效的问题。当你在Set中添加一个元素时,它在内部维护一个HashMap,其中键是你想在Set中输入的元素,值是虚拟常量。下面是add函数的内部实现。因此,HashMap中的所有键都将具有相同的常量值。

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

其他回答

如果您不介意要排序的集合,那么您可能有兴趣看看索引树映射项目。

增强的TreeSet/TreeMap提供了通过索引访问元素或获取元素索引的功能。实现基于更新RB树中的节点权重。所以这里没有迭代,也没有列表备份。

标准Java集合中缺少一些数据结构。

包(类似set,但可以多次包含元素)

UniqueList(有序列表,每个元素只能包含一次)

在这种情况下,你似乎需要一个唯一性列表

如果您需要灵活的数据结构,您可能会对谷歌Collections感兴趣

如果你要在一个集合中通过索引进行大量的随机访问,你可以得到它的元素的数组视图:

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

但它有两个主要缺点:

它的内存效率不高,因为需要为整个集合创建一个数组。 如果集合被修改,视图就会过时。

请注意,只有2个基本的数据结构可以通过索引访问。

数组数据结构可以通过O(1)时间复杂度的索引访问,实现get(int index)操作。 LinkedList数据结构也可以通过索引访问,但要用O(n)时间复杂度来实现get(int index)操作。

在Java中,ArrayList是使用Array数据结构实现的。

而Set数据结构通常可以通过HashTable/HashMap或BalancedTree数据结构实现,为了快速检测元素是否存在并添加不存在的元素,通常一个实现良好的Set可以实现O(1)个时间复杂度包含操作。在Java中,HashSet是Set最常用的实现,它是通过调用HashMap API来实现的,HashMap是使用链表(Array和LinkedList的组合)来实现的。

由于Set可以通过不同的数据结构实现,因此没有get(int index)方法。

我能想到的在集合中使用数值索引的唯一原因是为了迭代。为此,请使用

for(A a : set) { 
   visit(a); 
}