集合之HashSet(含JDK1.8源码分析)
一、前言
我们已经分析了List接口下的ArrayList和LinkedList,以及Map接口下的HashMap、LinkedHashMap、TreeMap,接下来看的是Set接口下HashSet和LinkedHashSet,其实在分析完了HashMap、LinkedHashMap之后,再来看HashSet和LinkedHashSet就会非常简单。
四个关注点在hashSet上的答案

二、hashSet的数据结构
因为hashSet的底层是基于hashMap,所以hashSet的数据结构就是hashMap的数据结构,因为前面已经分析过了hashMap的数据结构,这里不再赘述。集合之HashMap(含JDK1.8源码分析)。
三、hashSet源码分析-属性及构造函数
3.1 类的继承关系
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
说明:实现了Set接口,其内定义了一些共有的操作。
3.2 类的属性
//版本序列号
static final long serialVersionUID = -5024744406713321676L; //基于map的操作
private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
说明:hashSet的底层是基于hashMap或linkedHashMap的,所以定义了一个HashMap的属性,又因为map是基于键值对来进行操作的,所以又定义了一个假的key-value中的value:PRESENT,注意此属性被final修饰,即值永远不会被改变,仅仅是在map操作时补一下value的位置。所有通过hashSet添加进来的key都对应同一个value值,PRESENT。
3.3 类的构造函数

如上所述,共有五种。这里说明一下hashSet下定义的基于两种不同的map操作的构造函数。
1、HashSet()型
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
说明:底层基于hashMap进行操作,红框中剩下的三种也是基于hashMap操作的。
2、HashSet(int initialCapacity, float loadFactor, boolean dummy)
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
说明:注意该构造方法不是public的,且注释中已经说该构造方法只会被LinkedHashSet使用,所以平常我们new HashSet的时候是不能用的,该方法只有在创建LinkedHashSet对象的时候:new LinkedHashSet()才会被调用,如下super(16, .75f, true)才会调用此方法。
/**
* Constructs a new, empty linked hash set with the default initial
* capacity (16) and load factor (0.75).
*/
public LinkedHashSet() {
super(16, .75f, true);
}
四、hashSet源码分析-核心函数
hashSet的add方法,contains方法,remove方法等等都是基于hashMap的操作方式,前面已经分析过,这里不再赘述。
4.1 add方法
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
4,2 remove方法
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>,
* if this set contains such an element. Returns <tt>true</tt> if
* this set contained the element (or equivalently, if this set
* changed as a result of the call). (This set will not contain the
* element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return <tt>true</tt> if the set contained the specified element
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
4.3 contains方法
/**
* Returns <tt>true</tt> if this set contains the specified element.
* More formally, returns <tt>true</tt> if and only if this set
* contains an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this set is to be tested
* @return <tt>true</tt> if this set contains the specified element
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
举例:
public class Test {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
hashSet.add("zs");
hashSet.add("ls");
hashSet.add("ww");
hashSet.add("zl");
hashSet.add(null);
hashSet.add("zs");
System.out.println(hashSet);
boolean zs1 = hashSet.remove("zs");
System.out.println("删除zs===" + zs1);
System.out.println(hashSet);
boolean zs = hashSet.contains("zs");
System.out.println("是否包含zs===" + zs);
}
}
结果:可见,hashSet允许空值,不允许重复数据,无序。
[ww, null, zl, ls, zs]
删除zs===true
[ww, null, zl, ls]
是否包含zs===false
五、总结
可见,hashSet是与hashMap相对应的,分析完hashMap再来看hashSet就很简单了。
集合之HashSet(含JDK1.8源码分析)的更多相关文章
- 集合之TreeSet(含JDK1.8源码分析)
一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...
- 集合之LinkedHashSet(含JDK1.8源码分析)
一.前言 上篇已经分析了Set接口下HashSet,我们发现其操作都是基于hashMap的,接下来看LinkedHashSet,其底层实现都是基于linkedHashMap的. 二.linkedHas ...
- 集合之HashMap(含JDK1.8源码分析)
一.前言 之前的List,讲了ArrayList.LinkedList,反映的是两种思想: (1)ArrayList以数组形式实现,顺序插入.查找快,插入.删除较慢 (2)LinkedList以链表形 ...
- 集合之LinkedList(含JDK1.8源码分析)
一.前言 LinkedList是基于链表实现的,所以先讲解一下什么是链表.链表原先是C/C++的概念,是一种线性的存储结构,意思是将要存储的数据存在一个存储单元里面,这个存储单元里面除了存放有待存储的 ...
- 集合之ArrayList(含JDK1.8源码分析)
一.ArrayList的数据结构 ArrayList底层的数据结构就是数组,数组元素类型为Object类型,即可以存放所有类型数据.我们对ArrayList类的实例的所有的操作(增删改查等),其底层都 ...
- 集合之TreeMap(含JDK1.8源码分析)
一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...
- 集合之LinkedHashMap(含JDK1.8源码分析)
一.前言 大多数的情况下,只要不涉及线程安全问题,map都可以使用hashMap,不过hashMap有一个问题,hashMap的迭代顺序不是hashMap的存储顺序,即hashMap中的元素是无序的. ...
- 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)
一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...
- 【集合框架】JDK1.8源码分析之HashMap(一) 转载
[集合框架]JDK1.8源码分析之HashMap(一) 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...
随机推荐
- linux普通用户提权操作
[root@test1 ~]# vim /etc/sudoers ## Allow root to run any commands anywhere root ALL=(ALL) ALLzhouyu ...
- 第1章 从开机加电到main函数之前的过程
主要讲解了80x86cpu在启动的时候时bios如何工作,以及如何最终转换到保护模式. 1.1 启动bios 80x86作为冯诺依曼结构下的cpu,工作模式也是取指执行,即cpu根据cs:ip寄存器的 ...
- 4、原生jdbc链接数据库常用资源名
原生jdbc链接数据库要素:#MySql:String url="jdbc:mysql://localhost:3306/数据库名";String name="root& ...
- WiFi-ESP8266入门http(3-3)网页认证上网-post请求-ESP8266程序
第一版 原型系统 连上西电的网 直接发送上网的认证信息 返回认证结果网页 成功上网 #include <ESP8266WiFi.h> #define Use_Serial Serial s ...
- ActiveMQ安装配置及使用 转发 https://www.cnblogs.com/hushaojun/p/6016709.html
ActiveMQ安装配置及使用 ActiveMQ介绍 ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JM ...
- Spring Boot设置上传文件大小
可以使用配置文件配置,也可以使用Bean在启动类中配置 配置文件为application.properties格式: spring.http.multipart.maxFileSize=10Mb sp ...
- BZOJ4061/Gym100624F CERC2012 Farm and Factory 最短路、切比雪夫距离
传送门--BZOJCH 传送门--Vjudge 设\(f_i\)表示\(i\)到\(1\)号点的最短距离,\(g_i\)表示\(i\)到\(2\)号点的最短距离,\(s_i\)表示\(n+1\)号点到 ...
- ODPS-Java-SDK快速入门
一.简介 核心接口包括:AliyunAccount,MaxCompute(SDK中使用原名ODPS)等常见对象组件 更多参见文档:https://help.aliyun.com/document_de ...
- React 系列教程
英文版:https://reactjs.org/docs/create-a-new-react-app.html 中文版:https://doc.react-china.org/docs/hello- ...
- ThinkPHP+JQuery实现文件的异步上传
前端代码 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF- ...