集合之HashSet(含JDK1.8源码分析)
一、前言
我们已经分析了List接口下的ArrayList和LinkedList,以及Map接口下的HashMap、LinkedHashMap、TreeMap,接下来看的是Set接口下HashSet和LinkedHashSet,其实在分析完了HashMap、LinkedHashMap之后,再来看HashSet和LinkedHashSet就会非常简单。
四个关注点在hashSet上的答案

二、hashSet的数据结构
因为hashSet的底层是基于hashMap,所以hashSet的数据结构就是hashMap的数据结构,因为前面已经分析过了hashMap的数据结构,这里不再赘述。集合之HashMap(含JDK1.8源码分析)。
三、hashSet源码分析-属性及构造函数
3.1 类的继承关系
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
说明:实现了Set接口,其内定义了一些共有的操作。
3.2 类的属性
//版本序列号
static final long serialVersionUID = -5024744406713321676L; //基于map的操作
private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
说明:hashSet的底层是基于hashMap或linkedHashMap的,所以定义了一个HashMap的属性,又因为map是基于键值对来进行操作的,所以又定义了一个假的key-value中的value:PRESENT,注意此属性被final修饰,即值永远不会被改变,仅仅是在map操作时补一下value的位置。所有通过hashSet添加进来的key都对应同一个value值,PRESENT。
3.3 类的构造函数
  
如上所述,共有五种。这里说明一下hashSet下定义的基于两种不同的map操作的构造函数。
1、HashSet()型
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
说明:底层基于hashMap进行操作,红框中剩下的三种也是基于hashMap操作的。
2、HashSet(int initialCapacity, float loadFactor, boolean dummy)
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
说明:注意该构造方法不是public的,且注释中已经说该构造方法只会被LinkedHashSet使用,所以平常我们new HashSet的时候是不能用的,该方法只有在创建LinkedHashSet对象的时候:new LinkedHashSet()才会被调用,如下super(16, .75f, true)才会调用此方法。
/**
* Constructs a new, empty linked hash set with the default initial
* capacity (16) and load factor (0.75).
*/
public LinkedHashSet() {
super(16, .75f, true);
}
四、hashSet源码分析-核心函数
hashSet的add方法,contains方法,remove方法等等都是基于hashMap的操作方式,前面已经分析过,这里不再赘述。
4.1 add方法
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
4,2 remove方法
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>,
* if this set contains such an element. Returns <tt>true</tt> if
* this set contained the element (or equivalently, if this set
* changed as a result of the call). (This set will not contain the
* element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return <tt>true</tt> if the set contained the specified element
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
4.3 contains方法
/**
* Returns <tt>true</tt> if this set contains the specified element.
* More formally, returns <tt>true</tt> if and only if this set
* contains an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this set is to be tested
* @return <tt>true</tt> if this set contains the specified element
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
举例:
public class Test {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet<>();
        hashSet.add("zs");
        hashSet.add("ls");
        hashSet.add("ww");
        hashSet.add("zl");
        hashSet.add(null);
        hashSet.add("zs");
        System.out.println(hashSet);
        boolean zs1 = hashSet.remove("zs");
        System.out.println("删除zs===" + zs1);
        System.out.println(hashSet);
        boolean zs = hashSet.contains("zs");
        System.out.println("是否包含zs===" + zs);
    }
}
结果:可见,hashSet允许空值,不允许重复数据,无序。
[ww, null, zl, ls, zs]
删除zs===true
[ww, null, zl, ls]
是否包含zs===false
五、总结
可见,hashSet是与hashMap相对应的,分析完hashMap再来看hashSet就很简单了。
集合之HashSet(含JDK1.8源码分析)的更多相关文章
- 集合之TreeSet(含JDK1.8源码分析)
		
一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...
 - 集合之LinkedHashSet(含JDK1.8源码分析)
		
一.前言 上篇已经分析了Set接口下HashSet,我们发现其操作都是基于hashMap的,接下来看LinkedHashSet,其底层实现都是基于linkedHashMap的. 二.linkedHas ...
 - 集合之HashMap(含JDK1.8源码分析)
		
一.前言 之前的List,讲了ArrayList.LinkedList,反映的是两种思想: (1)ArrayList以数组形式实现,顺序插入.查找快,插入.删除较慢 (2)LinkedList以链表形 ...
 - 集合之LinkedList(含JDK1.8源码分析)
		
一.前言 LinkedList是基于链表实现的,所以先讲解一下什么是链表.链表原先是C/C++的概念,是一种线性的存储结构,意思是将要存储的数据存在一个存储单元里面,这个存储单元里面除了存放有待存储的 ...
 - 集合之ArrayList(含JDK1.8源码分析)
		
一.ArrayList的数据结构 ArrayList底层的数据结构就是数组,数组元素类型为Object类型,即可以存放所有类型数据.我们对ArrayList类的实例的所有的操作(增删改查等),其底层都 ...
 - 集合之TreeMap(含JDK1.8源码分析)
		
一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...
 - 集合之LinkedHashMap(含JDK1.8源码分析)
		
一.前言 大多数的情况下,只要不涉及线程安全问题,map都可以使用hashMap,不过hashMap有一个问题,hashMap的迭代顺序不是hashMap的存储顺序,即hashMap中的元素是无序的. ...
 - 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)
		
一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...
 - 【集合框架】JDK1.8源码分析之HashMap(一) 转载
		
[集合框架]JDK1.8源码分析之HashMap(一) 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...
 
随机推荐
- 重置 Mac 上的 NVRAM 或 PRAM
			
https://support.apple.com/zh-cn/HT204063 如果 Mac 出现了与 NVRAM 或 PRAM 中储存的设置有关的问题,那么进行重置可能会有帮助. NVRAM( ...
 - BZOJ1061 NOI2008 志愿者招募 线性规划、费用流
			
传送门 一道思路很妙的线性规划网络流 设\(X_i\)表示第\(i\)天需要的人数,\(P_i\)表示第\(i\)种人雇佣的个数 那么我们可以列出一系列式子 比如说样例就可以列出三个式子: \(P_1 ...
 - JS /javascript 解除网页屏蔽右键(无法复制)的代码
			
javascript:(function() { function R(a){ona = "on"+a; if(window.addEventListener) window.ad ...
 - WindowsFormsHost下MouseWheel失效的解决办法
			
原文:WindowsFormsHost下MouseWheel失效的解决办法 看了网上有些写的用钩子,但是,在Stack Overflow上找到一个简便的方式
 - 在IDEA中构建Tomcat项目流程
			
在IDEA中构建Web项目流程 打开你的IDEA,跟着我走! 第一步:新建项目 第二步:找到Artifacts 点击绿色的+号,如图所示,点一下 这一步很关键,目的是设置输出格式为war包,如果你的项 ...
 - 【C#复习总结】析构函数
			
上篇提到析构函数,就顺便复习一下. 一 C# 析构函数 1.1 析构函数的定义 析构函数用于释放被占用的系统资源. 析构函数的名字由符号“-”加类名组成. 1.2 析构函数注意的问题 使用析构函数时, ...
 - [C#] LINQ之Join与GroupJoin
			
声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 一.编写Person与City类,如下: class Person { public int CityID { set; get; } ...
 - en
			
发音,这个应该算是学习英语的头等大事,如果没有机会和条件练好发音,也可以先将就着,不过后面你就会感觉到你说的人家可能会听不懂,我自己也曾经深受其害. 基本常用单词积累(大概2000~4000左右的词汇 ...
 - 我的微信小程序第三篇(app.json)
			
前言 端午节回家了,所以好多天没有更新,只想说还是待在家里舒服呀,妈妈各种做好吃的,小侄子侄女各种粘着我在室外玩,导致我三天下来不仅胖了一圈,还黑了一圈,上班第一天有同事就说我晒黑了,哭~~~,为了防 ...
 - jQuery中.html(“xxx”)和.append("xxx")有什么区别
			
append是追加,html是完全替换比如<p id="1"><p>123</p></p>$("#1").htm ...