Java集合之LinkedHashSet源码分析
1.简介
我们知道Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。根据源码实现中的注释我们可以知道LinkedHashSet是具有可预知迭代顺序的Set接口的哈希表和链接列表实现。此实现与HashSet的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序。使用示例如下:
package com.test.collections; import java.util.Iterator;
import java.util.LinkedHashSet; public class LinkedHashSetTest { /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedHashSet<Integer> set = new LinkedHashSet<Integer>();
set.add(2);
set.add(4);
set.add(1); Iterator<Integer> iter = set.iterator(); System.out.println(set.isEmpty());
System.out.println(set.size());
System.out.println(set.contains(2));
System.out.println(set.containsAll(c));
System.out.println(set.remove(2));
set.clear(); } }
2.继承结构
通过源代码可以看到LinkedHashSet继承了HashSet类,实现了Set、Cloneable以及Serializable接口,通过实现了Set接口我们知道不允许包含相同的元素。可是这个功能限制是如何实现的,我们来看下源代码就可以一目了然了。
3.源码解析
a:LinkedHashSet类中除了一个序列化ID没有其他的属性了,除了几个构造函数外没有其他的方法,其他的方法都是从HashSet直接继承而来,那就让我们从构造函数入手进行简单的分析。
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
从代码中给出的四个构造函数我们可以看出功能各异。我们先来看看简单的构造函数,第一个构造函数制定了两个参数,第二个制定了一个参数,第三个是没有参数设定一个空的构造函数,第四个针对集合的初始化的构造函数。如果我们想要清楚构造函数到底做了什么事情,那么我们需要弄清楚super()方法做了什么事情,以及addAll做了什么事情。看源码:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
Iterator<? extends E> e = c.iterator();
while (e.hasNext()) {
if (add(e.next()))
modified = true;
}
return modified;
}
原来这两个方法就是我们构造函数出现的。通过第一个方法HashSet,中有一个Map,那这又是什么呢。原来HashSet中有一个熟悉private transient HashMap<E,Object> map;这下我们明白了原来Set的底层是采用一个Map实现的。这个很重要的东西,通过Map的相关方法调用来模仿Set的功能。Super方法做的事情就是创建了一个指定大小和加载因子的Map,addAll()方法就是遍历这个集合然后依次将他们放入我们的Map中去,从而实现了用一个集合直接构造含有值的Set。
回过头来我们看看上面的四个构造方法。第一个方法就是制定了初始容量和加载因子的Set,第二个构造函数就是制定了初始容量的Set,使用系统默认的加载因子0.75。第三个构造函数就是直接调用了一个空的构造函数,默认初始化一个容量为16,加载因子为0.75的Set,最后一个就是使用一个集合初始化Set.
b:iterator()
public Iterator<E> iterator() {
return map.keySet().iterator();
}
iterator(),调用它就可以返回Set的迭代对象,底层是采用Map的keySet()方法实现的。
c:size()
public int size() {
return map.size();
}
直接返回了Map的容量就得到了Set的元素个数。
d:isEmpty()
public boolean isEmpty() {
return map.isEmpty();
}
也是调用map的集合是否为空方法。
e:contains()
public boolean contains(Object o) {
return map.containsKey(o);
}
判断是否含有某一个元素。
f:add()
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
g:remove()和clear()
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public void clear() {
map.clear();
}
删除元素的时候就是调用map的方法,clear也是一样。
4.其他(小结)
LinkedHashSet集合是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。Set的很多操作都是依赖Map来实现的,下次来学习下Map的源码相关。
Java集合之LinkedHashSet源码分析的更多相关文章
- 死磕 java集合之LinkedHashSet源码分析
问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...
- 死磕 java集合之DelayQueue源码分析
问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...
- 死磕 java集合之PriorityBlockingQueue源码分析
问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...
- 死磕 java集合之PriorityQueue源码分析
问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...
- 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计
问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...
- 死磕 java集合之ConcurrentHashMap源码分析(三)
本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...
- 死磕 java集合之ArrayDeque源码分析
问题 (1)什么是双端队列? (2)ArrayDeque是怎么实现双端队列的? (3)ArrayDeque是线程安全的吗? (4)ArrayDeque是有界的吗? 简介 双端队列是一种特殊的队列,它的 ...
- 死磕 java集合之LinkedList源码分析
问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...
- 【死磕 Java 集合】— ConcurrentSkipListMap源码分析
转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...
随机推荐
- fastboot完成自己主动命令
于Ubuntu13.10后来Ubuntu 14.04上,由APT安装fastboot以及adb该工具后, 发现fastboot在主动补充一个问题,, fastboot flash 自己主动有问题完成后 ...
- 编写高性能Javascript
编写高性能Javascript 多年来,Javascript一直在web应用开发中占据重要的地位,但是很多开发者往往忽视一些性能方面的知识,特别是随着计算机硬件的不断升级,开发者越发觉得Javascr ...
- android 内存泄漏分析技巧
java虚拟机执行一般都有一个内存界限,超过这个界限,就会报outofmemory.这个时候一般都是存在内存泄漏.解决内存泄漏问题,窃以为分为两个步骤:分析应用程序是否真的有内存泄漏,找到内存泄漏的地 ...
- Hadoop Streaming 得到mapreduce_map_input_file中遇到的问题的版本号
1.Hadoop Streaming,您可以在任务获得hadoop设置环境变量, 例如,使用awk书面map从而能获得:filename = ENVIRON["mapreduce_map_i ...
- Linux netstat订购具体解释
简单介绍 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics).masquerade 连接.多播成员 (Multicast Memb ...
- EF调用sp,EF自动生成返回类型
在sp中添加下面的红色部分,就是执行sp时的返回类型,后面在EF中添加该sp后,EF会在DBContext文件中,自动生成调用该sp的代码,包括返回类型等,如下: public virtual Obj ...
- Nyoj 城市平乱(图论)
描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市分别编号从1到M. 现在,小工军师告诉南将军,第K号城市发生了暴乱,南将军从各个部队都 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(17)-注册用户功能的细节处理(各种验证)
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(17)-注册用户功能的细节处理(各种验证) ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框 ...
- 浅谈 js 正则字面量 与 new RegExp 执行效率
原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...
- Chapter 2 User Authentication, Authorization, and Security(3):保server避免暴力袭击
原版的:http://blog.csdn.net/dba_huangzj/article/details/38756693,专题文件夹:http://blog.csdn.net/dba_huangzj ...