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

属性

//底层使用HashMap来实现
private transient HashMap<E,Object> map;//虚拟的Object对象作为HashMap的value
private 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<? extends E> 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<K,V> 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++;  //添加<k,v>
    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"));//结果:true
set.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("张三")));//true
System.out.println(set.add(new People("张三")));//true

情景2

//两次都是添加p1
HashSet set=new HashSet();People p1=new People("张三");
System.out.println(set.add(p1));//true
System.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));//true
System.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

HashSet源码分析相关推荐

  1. 【Java源码分析】LinkedHashSet和HashSet源码分析

    类的定义 public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, ...

  2. java ee是什么_死磕 java集合之HashSet源码分析

    问题 (1)集合(Collection)和集合(Set)有什么区别? (2)HashSet怎么保证添加元素不重复? (3)HashSet是否允许null元素? (4)HashSet是有序的吗? (5) ...

  3. 【Java入门提高篇】Day26 Java容器类详解(八)HashSet源码分析

    前面花了好几篇的篇幅把HashMap里里外外说了个遍,大家可能对于源码分析篇已经讳莫如深了.别慌别慌,这一篇来说说集合框架里最偷懒的一个家伙--HashSet,为什么说它是最偷懒的呢,先留个悬念,看完 ...

  4. HashSet源码分析:JDK源码系列

    1.简介 继续分析源码,上一篇文章把HashMap的分析完毕.本文开始分析HashSet简单的介绍一下. HashSet是一个无重复元素集合,内部使用HashMap实现,所以HashMap的特征耶继承 ...

  5. HashSet源码分析 jdk1.6

    Set的特点:Set元素无顺序,且元素不可以重复. 1.定义 public class HashSet<E> extends AbstractSet<E> implements ...

  6. Java集合之HashSet源码分析

    概述 HashSet是基于HashMap来实现的, 底层采用HashMap的key来保存数据, 借此实现元素不重复, 因此HashSet的实现比较简单, 基本上的都是直接调用底层HashMap的相关方 ...

  7. HashSet源码分析 1

    hashSet内部是利用hashMap实现的,将值存在hashmap的key上这也是为什么hashset不允许存取重复值得原因. 数据结构 private transient HashMap<E ...

  8. JAVA集合专题+源码分析

    文章目录 Java集合专题 集合和数组的区别 数组 集合 区别 集合体系结构介绍 单列集合 [Collection ] Collection接口 迭代器 迭代器原理 增强for循环 List接口 对集 ...

  9. Java学习集合源码分析

    集合源码分析 1.集合存在的原因 可以用数组来表示集合,那为什么还需要集合? 1)数组的缺陷 ​ 在创建数组时,必须指定长度,一旦指定便不能改变 数组保存必须是同一个类型的数据 数组的增加和删除不方便 ...

最新文章

  1. 只能看到部分局域网计算机,为什么局域网中只能看到部分电脑
  2. mongodb的增、删、改、插的一个实例
  3. 周志华讲座---关于人工智能---科普性质---天地工学讲坛2017.11.30
  4. 程序员面试拼多多,来看看这些面试题你掌握的有多少呢?
  5. Java POI 导出EXCEL经典实现 Java导出Excel
  6. 数据结构:超好用的数据结构与算法可视化工具(USFCA旧金山大学)
  7. WindowsAPI详解——GetCurrentDirectory 获得程序当前目录
  8. Node.js入门 - 永恒的Hello World!
  9. 从零开始学Pytorch(七)之卷积神经网络
  10. gm(GraphicsMagick)图片中文水印乱码问题
  11. boost安装_Boost编译与使用
  12. 大胆尝试随需消费的软件培训模式
  13. VSTO打包加载项 WPS可用 Advanced Installer
  14. 计算机病毒手动查杀,如何手动查杀计算机病毒
  15. Frodo and pillows
  16. 阿里万亿交易量级下的秒级监控
  17. 配色工具Material Design
  18. 20元一支的洗面奶,7天卖了上万,他们是如何做到的?
  19. Maya2019 XGen的Utility面板内容为空
  20. 游戏辅助脚本(python)

热门文章

  1. 2021贵州毕节高考成绩查询,2021贵州毕节选调生考试排名查询入口-时间(已开通)...
  2. php调用dll函数,[转载]matlab调用DLL中的函数
  3. 高等学校精品规划教材 计算机专业英语,计算机专业英语
  4. 量化延时法时间测量_「交易技术前沿」交易系统低延时测试与分析
  5. oracle解析失败事件,ORACLE诊断事件及深入解析10053事件
  6. Spring的AOP思想和实现AOP思想的框架AspectJ
  7. python中split的用法取第二个分片_python中split()函数的用法
  8. java面试 socket_【面试题】Java 的通信编程,编程题(或问答),用JAVA SOCKET 编程,读服务器几个字符,再写入本地显示?...
  9. 计算机显示器不清楚跟电池有关系吗,电脑液晶显示器显像模糊是什么原因
  10. cydia收费插件源_Cydia消失了怎么办 Cydia错误汇总介绍【图文】