博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HashSet源码分析
阅读量:5991 次
发布时间:2019-06-20

本文共 3661 字,大约阅读时间需要 12 分钟。

HashSet底层是HashMap实现的,关于HashMap的分析请移步到

属性

//底层使用HashMap来实现private transient HashMap
map; //虚拟的Object对象作为HashMap的valueprivate static final Object PRESENT = new Object();

HashSet底层是使用HashMap实现的,由于HashMap存储的是<Key,Value>键值对,而HashSet不需要Value,所以HashSet内部使用了一个虚拟的Object对象作为底层HashMap的值。

构造方法

public HashSet() {    //底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。        map = new HashMap<>();    }        public HashSet(Collection
c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }

初始化HashSet时,可以指定初始化容量和负载因子。因为HashSet是由HashMap来实现,如果不指定,则默认值都与HashMap中的一样,即默认初始化容量为16,默认负载因子为0.75。

add方法

public boolean add(E e) {    return map.put(e, PRESENT)==null;} //HashMap的put方法public V put(K key, V value) {      //map为空表时,进行扩充      if (table == EMPTY_TABLE) {          inflateTable(threshold);      }      //如果key为null,直接定位到table[0]处,进行处理      if (key == null)          return putForNullKey(value);      //计算key的hash值      int hash = hash(key);      //根据key的hash,定位key在table中索引      int i = indexFor(hash, table.length);      //判断key是否存在      for (Entry
e = table[i]; e != null; e = e.next) { Object k; //如果key已存在,则覆盖原value //【判断key相等】:也就是判断两个Object是否相等 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //暂存旧值 V oldValue = e.value; //用新值覆盖旧值 e.value = value; e.recordAccess(this); //返回旧值(方法返回后,可能还要用到旧值) return oldValue; } }//key不存在 //修改次数+1 modCount++; //添加
addEntry(hash, key, value, i); return null; }

从源码可以看出,HashSet如果添加了重复的元素,即key已存在时,会进行覆盖操作。 借助该特点,可以使用HashSet实现去重操作。

 

面试题:

1.HashSet的实现原理?

2.Set中元素是无序的

HashSet set=new HashSet();set.add("a");set.add("b");set.add("c");set.add("d");System.out.println(set);//结果:[d,b,c,a]

3.HashSet不允许重复

情景0

//两次添加"a"HashSet set=new HashSet();System.out.println(set.add("a"));//结果:trueset.add("b");set.add("c");set.add("d");System.out.println(set.add("a"));//结果:false

情景1

//两次分别添加不同的对象。HashSet set=new HashSet(); System.out.println(set.add(new People("张三")));//trueSystem.out.println(set.add(new People("张三")));//true

情景2

//两次都是添加p1HashSet set=new HashSet();        People p1=new People("张三");System.out.println(set.add(p1));//trueSystem.out.println(set.add(p1));//false

情景3

//两次分别添加s1,s2(显然,s1和s2是不同的对象)。HashSet set=new HashSet();        String s1=new String("a");String s2=new String("a"); System.out.println(set.add(s1));//trueSystem.out.println(set.add(s2));//false

4.HashSet如何保证不重复的?

hashset底层用的hashmap实现,hashset实际上是没有value的,只是用了一个虚拟的value(Object PRESENT),每个key的值都是该value。

当要插入一个存在的对象时,hashmap对相同的key则进行value值覆盖操作,所以相当于用新的<key,PRESENT>覆盖掉旧的<key,PRESENT>。所以表面看起来没有插入新的重复元素,也就保证了不重复。

5.HashSet添加元素的过程

①HashCode

当HashSet在添加元素时,会先调用hashCode()方法,判断即将加入的元素的hashCode是否与集合中的元素有相同的,如果没有,则允许添加该元素。如果有相同的,则继续调用equals()方法,如果equals()方法返回true,则表示对象已经加入过了,不允许再添加了。否则,如果equels方法返回false,则允许添加新元素。
②equals

对于两个对象来说,如果使用equals返回true, 则这两个对象的hashcode一定相同。

对于两个对象来说,如果使用equals返回false,则这两个对象的hashcode不一定不相同(可以相同或者不同)。如果不同,可以提高性能。

对于Object类来说,不同的Object对象的hashcode值是不同的(hashCode值表示对象的地址)

String类的hashCode()方法重写了Object类的hashCode()方法,只要两个String对象的内容相同则认为hashCode相同,所以情景3比较特殊。

转载于:https://www.cnblogs.com/rouqinglangzi/p/10291706.html

你可能感兴趣的文章
使用Formik轻松开发更高质量的React表单(二)使用指南
查看>>
职场思想分享005 | 别让背后抱怨说别人坏话成为聊天习惯
查看>>
使用可重启AD DS 整理活动目录数据库
查看>>
SFB 项目经验-44-别以为Hyper-V比VMware差太多(仅个人观点,不喜误喷,谢谢)
查看>>
NDK编译错误expected specifier-qualifier-list before...
查看>>
老鸟手把手教你利用linux技能追求女孩子
查看>>
【.Net MF网络开发板研究-01】IP地址设定及简单web演示
查看>>
如何构建Keepalived+HAProxy实现高可用,负载均衡,动静分离。
查看>>
Percona XtraDB Cluster Installation Guide
查看>>
性能测试培训总结-message函数
查看>>
在notepad++中使用jslint检查javascript代码
查看>>
【奇葩的需求】对整个数据库里的所有表的所有字段的数据操作
查看>>
PHP5.3中 in_array()的一个坑
查看>>
[网络协议] HTTP状态码
查看>>
《鸟哥的Linux私房菜》13章shel script习题答案
查看>>
安装Windows Nano Server虚拟机
查看>>
Android系统的开机画面显示过程分析(6)
查看>>
声控公司Nuance
查看>>
海尔云电视引领“家庭云”风暴
查看>>
扎克伯格潜水Google+为什么?
查看>>