Set不重复原因

Java中的Set集合 怎么保障不重复? 

大家可能都知道Set是一个无序的不可以重复的集合。凡事想一个为什么? 
打开源码看一眼: 
Set是一个接口,常用的Set实现类那就是HashSet了。 
------------------------------------------------- 
public HashSet() { 
map = new HashMap<E,Object>(); 
    } 
------------------------------------------------- 

这是HashSet的构造方法。 可以看到HashSet内部其实就是一个HashMap 
【添加元素的方法】 
/**  
     * 如果此set中尚未包含指定元素,则添加指定元素。  
     * 更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2))  
     * 的元素e2,则向此set 添加指定的元素e。  
     * 如果此set已包含该元素,则该调用不更改set并返回false。  
     *  
     * 底层实际将将该元素作为key放入HashMap。  
     * 由于HashMap的put()方法添加key-value对时,当新放入HashMap的Entry中key  
     * 与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true),  
     * 新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变,  
     * 因此如果向HashSet中添加一个已经存在的元素时,新添加的集合元素将不会被放入HashMap中,  
     * 原来的元素也不会有任何改变,这也就满足了Set中元素不重复的特性。  
     * @param e 将添加到此set中的元素。  
     * @return 如果此set尚未包含指定元素,则返回true。  
     */ 
public boolean add(E e) { 
return map.put(e, PRESENT)==null; 
    } 
看一下map的定义: 
HashSet 中定义了这样的两个变量: 
    private transient HashMap<E,Object> map; 
    private static final Object PRESENT = new Object(); 
我们再看一下上面的 add() 方法。 
map.put(o, PRESENT)==null 
实际执行的是 map 的方法,并且我们添加的对象是 map 中的 key,value 是执行的同一个对象 PRESENT. 
因为map中的key是不允许重复的,所以set中的元素不能重复。  
============================================================================== 
根本问题还是没有解决那继续问?为什么HashMap中的Key不允许重复? 
HashMap的往里放元素的源码!!! 

public V put(K key, V value) { 
        if (key == null) 
            return putForNullKey(value); 
        int hash = hash(key.hashCode()); 
        int i = indexFor(hash, table.length); 
        //遍历链表 
        for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
            Object k; 
            //如果key在链表中已存在,则替换为新value  HashMap 可以重复put同一个Key值不同的对象。 
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
                V oldValue = e.value; 
                e.value = value; 
                e.recordAccess(this); 
                return oldValue; 
            } 
        } 

        modCount++; 
        addEntry(hash, key, value, i); 
        return null; 
    } 

分步骤判断添加的Key值: 
1、取到新添加Key值得hashCode值。 
2、确定数组的index 根据Key的hashCode值和当前table的长度按位取并  h & (length-1); 
    按位取并,作用上相当于取模mod或者取余%。 
    这意味着数组下标相同,并不表示hashCode相同 
3、这里的hashcode在equals前面,JVM会先判断或运算||的前部分,当这一前部分为true的时候判断终止,返回true(这是为了提高JVM的效率),所以当hashcode不同的时候,equals是不会执行的。 


总结为什么Set里面不能有重复? 
因为HashMap在put一个Key时会判断,将要放进去的Key的hash值与 目前HashMap中定位到的那个Key的hash值比较。 
如果hash值相当,继续比较 这两个对象的地址或者内容是否相当。 
如果相当:判断出来要添加的Key与HashMap中的Key重复,把Value的值给替换成最新的。 
HashSet中的Value是一个固定值PRESENT。 所以修改不修改无所谓。 
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值