集合之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对之前做了较大的优化 ...
随机推荐
- maven 标签classifier 研究一下
研究一下maven的标签: <dependency> <groupId>io.netty</groupId> <artifactId>netty-tcn ...
- springcloud 服务注册、反注册 AOP 拦截,实现自定义功能
@Aspect@Component@Order(1000)public class EurekaServerAspect {private Logger logger = Logger.getLogg ...
- P2690 接苹果 (DP)
补一下dp的思路: dp[i][j]表示第 i 分钟转 j 次所得到的最大值.很容易得到这个dp的推导式. 图中¢()函数表示成立为1, 不成立为0的函数. #include<cmath> ...
- 深入理解 Object.defineProperty 及实现数据双向绑定
Object.defineProperty() 和 Proxy 对象,都可以用来对数据的劫持操作.何为数据劫持呢?就是在我们访问或者修改某个对象的某个属性的时候,通过一段代码进行拦截行为,然后进行额外 ...
- 利用Oracle分析函数row_number和sys_connect_by_path实现多行数据合并为一行
emo场景,以oracle自带库中的表emp为例: select ename,deptno from emp order by deptno; ENAME DEPTNO CLARK 10 KING 1 ...
- SkylineGlobe TerraExplorer Pro 7.0 Web 控件版 第一行示例代码
SkylineGlobe TerraExplorer Pro 7.0 是原生的64位应用程序,在Web端用插件方式开发的第一行示例代码如下: 常规代码,需要IE64位: <!DOCTYPE ht ...
- Spring整合ActiveMQ及多个Queue消息监听的配置
消息队列(MQ)越来越火,在java开发的项目也属于比较常见的技术,MQ的相关使用也成java开发人员必备的技能.笔者公司采用的MQ是ActiveMQ,且消息都是用的点对点的模式.本文记录了实 ...
- Asp.Net Core实战(干货)
序言 使用.NET Core,团队可以更容易专注的在.net core上工作.比如核心类库(如System.Collections)的更改仍然需要与.NET Framework相同的活力,但是ASP. ...
- 开源纯C#工控网关+组态软件(二)工控网关的实现
一. 工控网关是什么 网关是物联网和工控系统的核心组件.网关起的是承上启下的作用.上即上位机,电脑/触屏监控系统.MES这些:下即下位机,包括PLC.传感器.嵌入式芯片等. 不同厂家的下位机,往往 ...
- 第十二届湖南省赛 (B - 有向无环图 )(拓扑排序+思维)好题
Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始.点 v 结束的路径). 为了方便,点用 1,2,…,n 编号. 设 count(x,y) 表示点 x 到点 y ...