java源码阅读HashSet
1类签名与注解
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
此类实现Set接口,由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证。特别是,它不能保证顺序在一段时间内保持不变(HashMap的扩容重hash)。 这个类允许null元素。
请注意,此实现不同步。 如果多个线程并发访问哈希集,并且至少有一个线程修改该集合,那么它必须在外部进行同步。 这通常通过在自然地封装集合的一些对象上进行同步来实现。 如果没有这样的对象存在,那么该集合应该使用Collections.synchronizedSet方法“包装”。 这最好在创建时完成,以防止对该集合的意外不同步访问:
Set s = Collections.synchronizedSet(new HashSet(...));
该类iterator方法返回的迭代器是故障快速的。此机制在HashMap一节中有详细讲述。
2属性
static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Map中的一个虚拟值
private static final Object PRESENT = new Object();
HashSet是通过HashMap实现的,所以内部持有map的引用,Set的值对应着Map中的key,但是每次map的插入需要是<key,value>的键值对,所以就有了虚拟的value对象,就是PRESENT。
3构造方法
//1默认
public HashSet() {
map = new HashMap<>();
} //2通过集合构造
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
} //3指定HashMap的初始化容量和负载因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
} //4指定HashMap的初始化容量
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
} //5指定初始化容量和负载因子,内部通过LinkedHashMap实现
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
注意:构造方法5的dummy参数其实没有特别的意义,唯一作用是通过多一个参数来区别构造方法3(方法重载)。
4常用方法
(1)add
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
(2)remove
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
(3)contains
public boolean contains(Object o) {
return map.containsKey(o);
}
(4)其他常用
public Iterator<E> iterator() {
return map.keySet().iterator();
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
HashSet的常用方法都是通过调用HashMap的方法实现的。
5其他
(1)clone
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
(2)序列化与反序列化
//序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject(); // Write out HashMap capacity and load factor
s.writeInt(map.capacity());
s.writeFloat(map.loadFactor()); // Write out size
s.writeInt(map.size()); // Write out all elements in the proper order.
for (E e : map.keySet())
s.writeObject(e);
} //反序列化
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject(); // 读capacity(检查非负).
int capacity = s.readInt();
if (capacity < 0) {
throw new InvalidObjectException("Illegal capacity: " + capacity);
} // 读负载因子(不能为null).
float loadFactor = s.readFloat();
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new InvalidObjectException("Illegal load factor: " + loadFactor);
} // Read size and verify non-negative.
int size = s.readInt();
if (size < 0) {
throw new InvalidObjectException("Illegal size: " + size);
}
// 计算需要的capacity
capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
HashMap.MAXIMUM_CAPACITY); // Constructing the backing map will lazily create an array when the first element is
// added, so check it before construction. Call HashMap.tableSizeFor to compute the
// actual allocation size. Check Map.Entry[].class since it's the nearest public type to
// what is actually created. SharedSecrets.getJavaOISAccess()
.checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity)); // 构造HashMap对象
map = (((HashSet<?>)this) instanceof LinkedHashSet ?
new LinkedHashMap<E,Object>(capacity, loadFactor) :
new HashMap<E,Object>(capacity, loadFactor)); // 往HashMap中添加键值对
for (int i=0; i<size; i++) {
@SuppressWarnings("unchecked")
E e = (E) s.readObject();
map.put(e, PRESENT);
}
}
(3)equals
HashSet类中没有实现equls方法,而是从父类AbstractSet中继承过来的。AbstractSet中equls实现如下:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
if (c.size() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))
return true;
}
return false;
}
equals首先判断是否引用同1个对象,若是则返回true。
否则,判断是否都是Set类型的,若不是则返回false。
若是,判断是否都有相等的size,若不是则返回false。
若是,则调用containsAll是否包含所有元素,若是则返回true,否则返回false。
java源码阅读HashSet的更多相关文章
- Java源码阅读的真实体会(一种学习思路)
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...
- Java源码阅读的真实体会(一种学习思路)【转】
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+ ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
- [收藏] Java源码阅读的真实体会
收藏自http://www.iteye.com/topic/1113732 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我 ...
- JDK 1.8源码阅读 HashSet
一,前言 类实现Set接口,由哈希表支持(实际上是一个 HashMap集合).HashSet集合不能保证的迭代顺序与元素存储顺序相同.HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依 ...
- java源码阅读Hashtable
1类签名与注释 public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, C ...
- Java源码阅读Stack
Stack(栈)实现了一个后进先出(LIFO)的数据结构.该类继承了Vector类,是通过调用父类Vector的方法实现基本操作的. Stack共有以下五个操作: put:将元素压入栈顶. pop:弹 ...
- Java源码阅读顺序
阅读顺序参考链接:https://blog.csdn.net/qq_21033663/article/details/79571506 阅读源码:JDK 8 计划阅读的package: 1.java. ...
- java源码阅读LinkedBlockingQueue
1类签名与简介 public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements Blocking ...
随机推荐
- 正则表达式 re模块 collections模块
根据手机号码一共11位并且是只以13.14.15.18开头的数字这些特点,我们用python写了如下代码: while True: phone_number = input('please input ...
- POJ2245 Lotto
Lotto Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6634 Accepted: 4201 Description ...
- linux驱动基础系列--linux spi驱动框架分析
前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...
- Kuangbin 带你飞-基础计算几何专题 题解
专题基本全都是模版应用.贴一下模版 平面最近点对 const double INF = 1e16; ; struct Point { int x,y; int type; }; double dist ...
- 【 Keepalived 】Nginx or Http 主-备模式
一.主-备模式: 操作系统:centos 6.4 x64 ka1: 192.168.2.10 ka2: 192.168.2.11 vip: 192.168.2.200 ka1-master服务器配置 ...
- [TJOI2007]segment
题目描述 在一个 n*n 的平面上,在每一行中有一条线段,第 i 行的线段的左端点是(i, L(i)),右端点是(i, R(i)),其中 1 ≤ L(i) ≤ R(i) ≤ n. 你从(1, 1)点出 ...
- javascript实现网页返回顶部功能
在浏览网页时,我们一般是拖动滚动条向下滑动,浏览下面的内容,当页面超过单页时,右下角会出现一个回到顶部的图标,有些网站这个图标一直显示在右下角的. 有些网站使用锚链接来实现页面内容的跳转,但这种效果的 ...
- 使用 URLDecoder 和 URLEncoder 对统一认证中的http地址转义字符进行处理
import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; ...
- redis发布订阅、HyperLogLog与GEO功能的介绍
一.发布订阅 1.模型 发布者发布消息,订阅者接收消息 2.API 2.1.publish 2.2.订阅 2.3.取消订阅 unsubsribe 2.4.其他api 二.HyperLogLog 极小空 ...
- Nodejs获取Azure Active Directory AccessToken
因为现有的代码已经迁入至Azure中,并且受AD保护,所以在获取数据时,需要传入Token后才可以获取到数据,那么第一步肯定是需要先提取到token var adal = require('adal- ...