学习JDK1.8集合源码之--HashSet
1. HashSet简介
HashSet是一个不可重复的无序集合,底层由HashMap实现存储,故HashSet是非线程安全的,由于HashSet使用HashMap的Key来存储元素,而HashMap的Key可以允许有一个null值,所以HashSet是可以存储null值的。
由于HashSet的不可重复性,在项目开发中可以利用这一点进行元素去重,但前提是在不考虑线程安全的问题基础上。
2. HashSet的继承关系
HashSet继承自AbstractSet,实现了Set、Cloneable、java.io.Serializable接口。
AbstractSet继承自AbstractCollection,实现了Set接口,此类并没有重写 AbstractCollection 类中的任何实现(包括add()方法)。它仅仅添加了 equals 和 hashCode 的实现。
实现了Set接口:表明本类是一个不包含重复元素的类,并最多包含一个null值。
实现了Cloneable接口:可以调用Object.clone方法返回该对象的浅拷贝。
实现了 java.io.Serializable 接口:可以启用其序列化功能,能通过序列化去传输。
3. HashSet的实现
1. 核心属性
//HashMap存储数据
private transient HashMap<E,Object> map;
//final修饰的不可改变的空对象
private static final Object PRESENT = new Object();
底层通过HashMap来进行数据的存储,HashMap的key来存储元素,value统一存储一个不可改变的空对象PRESENT,为什么要这么做呢?因为既然是通过HashMap存储数据,数据的移除操作也是通过HashMap的remove方法进行移除,而HashMap的remove方法会返回被移除的Value值,而把PRESENT设为final就能保证可以通过判断返回的值是否是PRESENT对象就可以判断是否移除成功。
2. 构造函数
//无参构造,实例化一个HashMap对象
public HashSet() {
map = new HashMap<>();
}
//带参构造,传入一个集合
public HashSet(Collection<? extends E> c) {
//因为HashMap的默认加载因子是0.75,当元素个数达到容量的0.75倍的时候便会自动扩容
//所以,这里取(int) (c.size()/.75f) + 1,为了避免实例化后的HashMap达到默认尺度
//因为HashMap的默认初始容量是16,所以取(int) (c.size()/.75f) + 1和16的最大值作为初始容量
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//带参构造,传入一个HashMap的初始容量
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//带参构造,传入HashMap的初始容量和加载因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
//带参构造(用于LinkedHashSet实现,不对外开放),传入HashMap的初始容量和加载因子,dummy参数用来和上一个构造函数作区分,表明实例化一个LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
3. 核心方法
//添加一个元素
public boolean add(E e) {
//调用HashMap的put方法,因为HashMap的Key不能重复,重复时会把添加的元素直接返回,成功则返回null
return map.put(e, PRESENT)==null;
} //调用HashMap的clear方法来清空元素
public void clear() {
map.clear();
} //调用HashMap的containsKey来判断是否包含元素o
public boolean contains(Object o) {
return map.containsKey(o);
} //通过调用HashMap的isEmpty方法来判断集合是否为空
public boolean isEmpty() {
return map.isEmpty();
} //返回迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
} //调用HashMap的remove方法来移除元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
} //HashMap的大小就是集合的大小
public int size() {
return map.size();
}
HashSet的基本元素操作都是通过调用HashMap的API来实现的,所以需要了解具体实现细节需要去学习HashMap。
4. HashSet的遍历
1. 通过Iterator迭代器
// 假设set是HashSet对象
for(Iterator iterator = set.iterator();
iterator.hasNext(); ) {
iterator.next();
}
2. foreach
// 假设set是HashSet对象,并且set中元素是String类型
String[] arr = (String[])set.toArray(new String[0]);
for (String str:arr)
System.out.println("for each : %s", str);
学习JDK1.8集合源码之--HashSet的更多相关文章
- 学习JDK1.8集合源码之--LinkedHashSet
1. LinkedHashSet简介 LinkedHashSet继承自HashSet,故拥有HashSet的全部API,LinkedHashSet内部实现简单,核心参数和方法都继承自HashSet,只 ...
- 学习JDK1.8集合源码之--HashMap
1. HashMap简介 HashMap是一种key-value结构存储数据的集合,是map集合的经典哈希实现. HashMap允许存储null键和null值,但null键最多只能有一个(HashSe ...
- 学习JDK1.8集合源码之--ArrayList
参考文档: https://cloud.tencent.com/developer/article/1145014 https://segmentfault.com/a/119000001857894 ...
- 学习JDK1.8集合源码之--WeakHashMap
1. WeakHashMap简介 WeakHashMap继承自AbstractMap,实现了Map接口. 和HashMap一样,WeakHashMap也是一种以key-value键值对的形式进行数据的 ...
- 学习JDK1.8集合源码之--ArrayDeque
1. ArrayDeque简介 ArrayDeque是基于数组实现的一种双端队列,既可以当成普通的队列用(先进先出),也可以当成栈来用(后进先出),故ArrayDeque完全可以代替Stack,Arr ...
- 学习JDK1.8集合源码之--Vector
1. Vector简介 Vector是JDK1.0版本就推出的一个类,和ArrayList一样,继承自AbstractList,实现了List.RandomAccess.Cloneable.java. ...
- 学习JDK1.8集合源码之--TreeMap
1. TreeMap简介 TreeMap继承自AbstractMap,实现了NavigableMap.Cloneable.java.io.Serializable接口.所以TreeMap也是一个key ...
- 学习JDK1.8集合源码之--LinkedHashMap
1. LinkedHashMap简介 LinkedHashMap继承自HashMap,实现了Map接口. LinkedHashMap是HashMap的一种有序实现(多态,HashMap的有序态),可以 ...
- 学习JDK1.8集合源码之--PriorityQueue
1. PriorityQueue简介 PriorityQueue是一种优先队列,不同于普通队列的先进先出原则,优先队列是按照元素的优先级出列,每次出列都是优先级最高的元素.优先队列的应用很多,最典型的 ...
随机推荐
- Java程序员面试题收集(1)
一.Java基础部分 1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: 1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪 ...
- jdk11下载安装及环境变量配置
jdk11下载安装及环境变量配置 官网地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-50666 ...
- CSS元素隐藏方法总结
display:none; visibility:hidden; opacity:0三者的区别 display:none; 该属性会让元素完全从DOM中消失,浏览器不渲染设置该属性的元素,不占据DOM ...
- 快速I/O 51node 1406
#include <bits/stdc++.h> using namespace std; #define LL long long typedef pair<int,int> ...
- Odoo文档管理/知识管理应用实践 - 上传附件
测试环境: Odoo8.0 Odoo中的文档管理/知识管理可用于保存采购.销售.生产等一系列业务流程中产生的文件.凭证,可关联到具体的每一笔业务操作:也能用于管理公司的合同.资料,创建知识库以分享内部 ...
- extern “C”的用法
引言 由于不同的代码互相调用起来很容易出错,甚至同一种代码但由不同的编译器编译,为实现C++代码调用其他C语言代码,会在C语言代码的部分加上extern "C",表明这段代码需要按 ...
- 构建工具Bazel入门
Bazel入门 原文:http://bazel.io/docs/getting-started.html 译者:chai2010 安装 安装过程请参考: http://bazel.io/docs/ ...
- 数据表中记录明明有,session.get(类.class, id);返回null
出现null的处理思路首先检查数据库中是否真的有这个记录 确实存在的,用接口查一下最大值,也是存在的,数据库连接正常 写sql也可以查得到 然而诡异的事情出现了 难道是一直在用的dao代码出了问题? ...
- 【One by one系列】一步步开始使用Redis吧(一)
One by one,一步步开始使用Redis吧(一) 最近有需求需要使用redis,之前也是随便用用,从来也没有归纳总结,今天想睡觉,但是又睡不着,外面阳光不错,气温回升了,2019年6月1日,成都 ...
- 在VS中编译Opencascade6.6.0
话说,OpenCASCADE团队真的很给力,版本更新速度也是嗖嗖地.依稀记得上次编译OCC,那时候的第三方库.OCC本身几何引擎库,全都得自己编译. 于是,编译过程之艰苦也就可想而知了.最近重换系统, ...