摘要:到此发现,实际上可以拆分成跟指的是,则是指实现了接口,这样看来,的实现其实就比较简单了,下面开始分析源码。
概述
在分析HashSet源码前,先看看HashSet的继承关系
HashSet继承关系
从上图可以看出,HashSet继承自AbstractSet,实现了Set接口,接着看一下源码中的注释
This class implements the Set interface, backed by a hash table
(actually a HashMapinstance). It makes no guarantees as to the
iteration order of the set; in particular, it does not guarantee that the
order will remain constant over time. This class permits the null element.
HashSet实现了Set接口,内部有一个哈希表支撑(实际上就是一个HashMap实例),它不保证迭代的顺序;尤其是,随着时间的变化,它不能保证set的迭代顺序保持不变。允许插入空值。
到此发现,HashSet实际上可以拆分成Hash跟Set,Hash指的是HashMap,Set则是指实现了Set接口,这样看来,HashSet的实现其实就比较简单了,下面开始分析源码。
正文
成员变量
//序列化ID static final long serialVersionUID = -5024744406713321676L; //内置的HashMap private transient HashMapmap; // 就是一个傀儡,填充HashMap的Value而已,没有实际意义 private static final Object PRESENT = new Object();
构造方法
空的构造方法
初始化一个空的HashMap
public HashSet() { map = new HashMap<>(); }
带有容量的构造方法
HashMap给定一个容量
public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); }
带有容量跟负载因子的构造方法
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor); }
带有容量跟负载因子,以及Value类型区分
dummy作为Value是基本类型跟引用类型,注意此处初始化的是一个LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
通过一个集合初始化
public HashSet(Collection extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
调用addAll方法
public boolean addAll(Collection extends E> c) { boolean modified = false; //循环遍历 for (E e : c) //如果set中没有此元素,添加成功 if (add(e)) modified = true; return modified; }
增加元素
添加一个元素,如果Map中存在,返回false,否则返回true
public boolean add(E e) { return map.put(e, PRESENT)==null; }
看一下Map的put方法
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key); int i = indexFor(hash, table.length); for (HashMapEntrye = table[i]; e != null; e = e.next) { Object k; //这里比较了hash值跟equals方法 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
所以Set元素必须复写hashcode跟equals方法,不然会导致元素错乱
删除元素
public boolean remove(Object o) { //直接调用map的方法 return map.remove(o)==PRESENT; }
clear
public void clear() {
//调用map的Clear方法
map.clear(); }
contains方法
public boolean contains(Object o) { 调用map的contains方法 return map.containsKey(o); }
isEmpty
public boolean isEmpty() { //调用map的isEmpty方法 return map.isEmpty(); }
迭代
public Iterator
//因为不需要value,所以只是调用了keySet的iterator
return map.keySet().iterator(); }
分析了一下,其实最终的底层实现都是在调用HashMap的方法,所以了解了HashMap的源码之后,HashSet其实就会比较简单了
总结
HashSet是非线程安全的,允许插入空元素
HashSet不允许重复元素
HashSet的Key需要复写hashcode跟equals方法
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/67728.html
摘要:源码分析属性内部使用虚拟对象,用来作为放到中构造方法非,主要是给使用的构造方法都是调用对应的构造方法。遍历元素直接调用的的迭代器。什么是机制是集合中的一种错误机制。当使用迭代器迭代时,如果发现集合有修改,则快速失败做出响应,抛出异常。 简介 集合,这个概念有点模糊。 广义上来讲,java中的集合是指java.util包下面的容器类,包括和Collection及Map相关的所有类。 中...
摘要:本文是作者自己对中线程的状态线程间协作相关使用的理解与总结,不对之处,望指出,共勉。当中的的数目而不是已占用的位置数大于集合番一文通版集合番一文通版垃圾回收机制讲得很透彻,深入浅出。 一小时搞明白自定义注解 Annotation(注解)就是 Java 提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解) 是一个接口,程序可以通过...
摘要:原文地址游客前言金三银四,很多同学心里大概都准备着年后找工作或者跳槽。最近有很多同学都在交流群里求大厂面试题。 最近整理了一波面试题,包括安卓JAVA方面的,目前大厂还是以安卓源码,算法,以及数据结构为主,有一些中小型公司也会问到混合开发的知识,至于我为什么倾向于混合开发,我的一句话就是走上编程之路,将来你要学不仅仅是这些,丰富自己方能与世接轨,做好全栈的装备。 原文地址:游客kutd...
摘要:三系列用于保存键值对,无论是,还是已弃用的或者线程安全的等,都是基于红黑树。是完全基于红黑树的,并在此基础上实现了接口。可以看到,只有红黑树,且红黑树是通过内部类来实现的。 JDK容器 前言 阅读JDK源码有段时间了,准备以博客的形式记录下来,也方便复习时查阅,本文参考JDK1.8源码。 一、Collection Collection是所有容器的基类,定义了一些基础方法。List、Se...
阅读 1159·2021-11-15 18:00
阅读 1736·2021-10-08 10:15
阅读 708·2021-09-04 16:48
阅读 2336·2021-09-04 16:48
阅读 1290·2019-08-29 18:40
阅读 817·2019-08-29 13:08
阅读 2962·2019-08-26 14:06
阅读 1078·2019-08-26 13:35