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的更多相关文章

  1. Java源码阅读的真实体会(一种学习思路)

    Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...

  2. Java源码阅读的真实体会(一种学习思路)【转】

    Java源码阅读的真实体会(一种学习思路)   刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+ ...

  3. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

  4. [收藏] Java源码阅读的真实体会

    收藏自http://www.iteye.com/topic/1113732 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我 ...

  5. JDK 1.8源码阅读 HashSet

    一,前言 类实现Set接口,由哈希表支持(实际上是一个 HashMap集合).HashSet集合不能保证的迭代顺序与元素存储顺序相同.HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依 ...

  6. java源码阅读Hashtable

    1类签名与注释 public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, C ...

  7. Java源码阅读Stack

    Stack(栈)实现了一个后进先出(LIFO)的数据结构.该类继承了Vector类,是通过调用父类Vector的方法实现基本操作的. Stack共有以下五个操作: put:将元素压入栈顶. pop:弹 ...

  8. Java源码阅读顺序

    阅读顺序参考链接:https://blog.csdn.net/qq_21033663/article/details/79571506 阅读源码:JDK 8 计划阅读的package: 1.java. ...

  9. java源码阅读LinkedBlockingQueue

    1类签名与简介 public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements Blocking ...

随机推荐

  1. Windows下搭建本地SVN服务器【转】

    转自:http://www.linuxidc.com/Linux/2015-01/111563.htm 本文介绍Windows下搭建本地SVN服务器的方法,网上资料比较少也比较旧,大都介绍的是旧版本S ...

  2. 开源的zip_unzip库

    zip/unzip源码交叉编译 http://blog.chinaunix.net/uid-20288609-id-10016.html zlib 1.2.11 http://www.zlib.net ...

  3. iOS设计模式 —— KVC

    刨根问底KVC KVC 全称 key valued coding 键值编码 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性 ...

  4. javascript中a标签把href属性设置为“javascript:void(0)”还是会打开空白页面的问题

    在项目中有个位置的点击a标签这里要加一个权限判断,但是之前使用的是js动态添加a标签,href的属性值是一个url,但是我要做权限判断之后,我的url就不能设置在href属性中了,这样的话我可以在a标 ...

  5. jquery请求格式和返回类型 汇总

    常规请求基本格式 1 [WebMethod] 2 public string SayHello(string name) 3 { 4 return "Hello " + name; ...

  6. Selenium2+python自动化58-读取Excel数据(xlrd)【转载】

    前言 当登录的账号有多个的时候,我们一般用excel存放测试数据,本节课介绍,python读取excel方法,并保存为字典格式. 一.环境准备 1.先安装xlrd模块,打开cmd,输入pip inst ...

  7. Android局域网访问webservice以及其中的一些问题

    应老师的要求,要做个安卓app,实现备份app上的数据到服务器上的mongodb上,网上搜了下相关的实现方式.利用webservice技术,具体来说就是客户端直接调用服务器端的接口.之前从来没接触这玩 ...

  8. Win10系统解决C盘分区限制一半的问题

    1,按照网上的方法还不行,如链接 2,安装如下软件,里面有激活码,链接 链接:https://pan.baidu.com/s/14ifYpnCMGwJIbgykTYQR6Q 密码:whh3 3,安装并 ...

  9. 架构体系需要进一步研究探索的V2路线图

    https://github.com/dawnbreaks/mysql2redis/blob/master/README.md http://blog.163.com/zhangjie_0303/bl ...

  10. 【转】持续集成 Sonar 平台搭建及 Sonar 自定义规则打包部署篇

    引言 基于阿里开发手册的sonar自定义插件工程 开源地址: https://github.com/tigerge000/sonar-java-custom-rules.git由于最近来问童鞋,就算写 ...