今天面试官问我:Set如何保证不重复?
答案 0 :(得分:2)
答案在于add
方法的源代码。例如,在TreeSet
的源代码中,add方法实现如下:
public boolean add(E e)
{
return m.put(e, PRESENT)==null;
}
其中,PRESENT
是Object
类的对象。而m
是NavigableMap
的对象。此NavigableMap
m
用于将e
元素key
和PRESENT
作为value
存储到给定键e
。因此m
中的每个键都具有相同的对象PRESENT
。 oracle doc中定义的put
Map
方法是:
将指定的值与此映射中的指定键相关联。如果映射先前包含键的映射,则替换旧值。
...
...
返回:与键关联的上一个值,如果没有键的映射,则返回 null。 (null返回也可以指示映射先前将null与key关联。)
因此,当您将重复元素置于集合中时,此元素将作为值NavigableMap
放入PRESENT
作为键。如果NavigableMap
中没有此密钥,则put
方法返回null
,因此
m.put(e,PRESENT)==null
返回true,我们知道元素已添加。如果密钥已在NavigableMap
中出现,则put
方法会使用PRESENT覆盖value
key
内的e
,并返回旧值(即PRESENT)因此
NavigableMap
返回m.put(e,PRESENT)==null
,我们知道该元素未添加。
答案 1 :(得分:1)
Set是一种抽象数据类型,可以通过多种方式实现。它本身就是合同的规范;因此它不保证任何东西。这取决于接口的实现,以保证合同得到履行。
因此,了解实现的工作方式和原因会更有趣。一些常见的实现是:
HashSet
TreeSet
EnumSet
和BitSet
ConcurrentSkipListSet
CopyOnWriteArraySet
在求职面试中,你会回复上述内容并提出解释任何一项实施的细节。面试官应该已经知道其中的一些,除非被问到,否则开始对他们进行漫无操作对你不利。
答案 2 :(得分:1)
从规范的角度来看,它通过例如如果您尝试添加重复项,请指定add
方法必须执行的操作。 add
方法的文档说明了这一点,例如:
如果指定的元素尚不存在,则将其添加到此集合中 (可选操作)。更正式地,将指定的元素e添加到 如果集合中不包含元素e2(e == null? e2 == null:e.equals(e2))。如果此集已包含元素, 调用使集合保持不变并返回false。结合 对构造函数的限制,这确保了永远不会 包含重复的元素。
来自同一页面(http://docs.oracle.com/javase/6/docs/api/java/util/Set.html):
对于构造函数的额外规定,毫不奇怪,所有构造函数都必须创建一个不包含重复元素的集合(如上所定义)。
(为了完整起见,还有关于equals
和hashCode
的规定,以确保Set
正确地模拟集合抽象。)