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 ...
随机推荐
- ZigBee MAC层(上)
1. 介绍 ZigBee MAC层,即IEEE 802.15.4 MAC层,这里主要介绍了802.15.4-2003版本 MAC层处理所有对物理无线信道的访问控制,并负责下面的任务 - 为协调器生成网 ...
- LINUX环境下的GUN MAKE学习笔记(二)
第三章:makefile总述 3.1makefile的内容 在一个完整的makefile中,包含显示规则.隐含规则.变量定义.指示符和注释.下面讨论一些基本概念: 显示规则:它描述了在何种情况下如何更 ...
- POI导入导出小案例
一.HSSF 97-2003 需要jar:poi-3.9.jar 简单示例:生成EXCEL //93---2003 String [] titlie={"id","nam ...
- Jxl、JxCell图表导出功能的实现
最近接触过许多报表导出功能,也用过多种工具进行导出功能的实现,但对于图表的导出一直没有仔细的去展开研究和探讨,直到最近略微整理了下这方面的需求和技术攻克. 首先导出excel功能的实现主要有JXL.J ...
- poj 2264(LCS)
Advanced Fruits Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2158 Accepted: 1066 ...
- C# DataGridView分页显示
//导入命名空间部分省略 DBClass.DBExecute dbexecute = new DBExecute(); string connectionString = @"Data So ...
- Vmware vSphere常见问题及解决办法
Vmware vSphere常见问题及解决办法 日期:2012-6-29来源:51cto Vmware vSphere 12 1. 虚拟机文件被锁,无法正常 power on 故障状态: 启动虚拟 ...
- [centos6.5] 把xampp的htdocs改为其他目录
vim /opt/lampp/etc/httpd.conf DocumentRoot "/opt/lampp/htdocs" 改为 DocumentRoot "/var/ ...
- Validate on POST data
1. Basic validate on bean's attribute. @Notnull @Max @Min @Pattern ... 2. Validate by logic 1) pass ...
- FFT&NTT&多项式相关
打了FFT 感觉以后多项式不虚了 ~滑稽~ PS 关于详见没写完.... code #include<cmath> #include<cstdio> #include<c ...