我是靠谱客的博主 甜甜外套,这篇文章主要介绍关于java中set集合的除重原理,现在分享给大家,希望可以做个参考。

Set<E>是单列集合,里面元素不可重复,元素存取无序,元素无索引的根节点
 创建对象:Set<E> 集合名 = new HashSet<E>();

Set集合的除重,是发生在调用add()方法时。下面,简单的看一下add()方法的底层代码

在HashSet里的add()方法源码如下

复制代码
1
2
3
public boolean add(E e) {         return map.put(e, PRESENT)==null;     }

我们可以看到,返回的是 map里put方法返回值跟null的比较。若添加成功,则返回True,失败是Fale。

看一下map里put方法,源码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; 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; }

这里只粗略的讲一下Set集合是如何除重的,所以很多跟返回值无关的代码不给予解释。

整个代码的功能分为

复制代码
1
2
3
一、非空校验,Set集合只允许一个null。 二、遍历查找相同元素 三、返回null ,add()方法返回  null == null  即true。

以下将代码分块解释:

public V put(K key, V value) {
    第一部分:
     

复制代码
1
2
3
  if (table == EMPTY_TABLE) {         inflateTable(threshold);         }


        
    第二部分:
       

复制代码
1
2
if (key == null)       return putForNullKey(value);

       key == null 非空校验 -----> key的非空校验
       判断传入的参数是否为空

复制代码
1
2
3
4
5
6
7
若你传入的元素为空的话 --> return putForNullKey(value); -->结束put方法并把方法的结果返回给调用者(add)                     putForNullKey(value)-->见名知意 专门为放null值的方法             第二板块的作用:                 判断你传入的参数是不是null:                     若不是null,继续下面的判断                     若是null,把这个null值存到集合中,当是当你第二次传入null值的时候,不允许再添加null             -->Set集合可以有null值的元素,但是只能有一个!!!



    第三部分:
       

复制代码
1
2
int hash = hash(key);         int i = indexFor(hash, table.length);


       hash(Object k)方法如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
 final int hash(Object k) {             int h = hashSeed;             if (0 != h && k instanceof String) {                 return sun.misc.Hashing.stringHash32((String) k);             }             h ^= k.hashCode();             // This function ensures that hashCodes that differ only by             // constant multiples at each bit position have a bounded             // number of collisions (approximately 8 at default load factor).             h ^= (h >>> 20) ^ (h >>> 12);             return h ^ (h >>> 7) ^ (h >>> 4);     }
复制代码
1
2
        我们可以看到,hash(Object k)的返回值跟hashCode()有关.我们在自己定义一个类时,对hashCode()进行了重写,         hashCode()返回了运算后属性值的地址,通过比较hashCode()的值来判断是否是同一个对象.


    第四部分:
       

复制代码
1
2
3
4
5
6
7
8
9
for (Entry<K,V> e = table[i]; e != null; e = e.next) {             Object k;             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                 V oldValue = e.value;                 e.value = value;                 e.recordAccess(this);                 return oldValue;             }         }
复制代码
1
2
3
for (Entry<K,V> e = table[i]; e != null; e = e.next)   这个for循环是在做遍历,遍历老的Set集合,找有没有重复的元素,e接收了老的Set集合
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))    左边:e.hash == hash 通过比较属性值的地址,判断新传入的Set集合是否跟老Set集合的某个是同一个对象  右边:((k = e.key) == key || key.equals(k)))        左边:(k = e.key) == key         这是将老Set集合中的key的地址值赋给k,然后和新传入的key的地址值比较.         对于引用数据类型的对象,每次创建对象的地址值是不同的,所以k!=key         对于集合包装类的对象,拿对象名比较时,会拆箱比较基本数据类型的值,所以存在k == key.         右边:key.equals(k)          这里重写了equals方法,比较的是属性值是否相同.           
复制代码
1
2
3
4
5
6
7
8
9
 //整理逻辑         若e.hash == hash,则说明对象的运算后属性地址值相同                             情况一:集合包装类,判断(k = e.key) == key,若相同,则执行if的语句, 返回跟新传入Set相同的老Set集合,即return oldValue             情况二:引用数据类型,判断key.equals(k)),若相同,则属性值相同,执行if的语句, 返回跟新传入Set相同的老Set集合,即return oldValue                若e.hash != hash,则说明对象的运算后属性地址值不相同,不执行if的语句   一定不是相同的对象         

Integer类型的hashCode怎么说? 
查看Integer源码可知,Integer的hashCode方法return 是value,也就是Integer的值。        
        
    第五部分:    

复制代码
1
2
3
modCount++; addEntry(hash, key, value, i); return null;

    //新传入的Set集合,非空且与老集合没有相同的元素,则返回null.
    }    
  
    也就是说,创建泛型是自己定义对象的Set集合时,要重写hashCode和equals (Set集合的去重依赖重写这两个方法)

最后

以上就是甜甜外套最近收集整理的关于关于java中set集合的除重原理的全部内容,更多相关关于java中set集合内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部