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源码分析的更多相关文章

  1. 死磕 java集合之LinkedHashSet源码分析

    问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...

  2. 死磕 java集合之DelayQueue源码分析

    问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...

  3. 死磕 java集合之PriorityBlockingQueue源码分析

    问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...

  4. 死磕 java集合之PriorityQueue源码分析

    问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...

  5. 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计

    问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...

  6. 死磕 java集合之ConcurrentHashMap源码分析(三)

    本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...

  7. 死磕 java集合之ArrayDeque源码分析

    问题 (1)什么是双端队列? (2)ArrayDeque是怎么实现双端队列的? (3)ArrayDeque是线程安全的吗? (4)ArrayDeque是有界的吗? 简介 双端队列是一种特殊的队列,它的 ...

  8. 死磕 java集合之LinkedList源码分析

    问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...

  9. 【死磕 Java 集合】— ConcurrentSkipListMap源码分析

    转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...

随机推荐

  1. 手把手教你如何加入到github的开源世界! (转)

    我曾经一直想加入到开源项目中,但是因为没有人指导流程,网上看了很多,基本都是说了个大概,如果你也是一个初出茅庐的人,那么,我将以自己提交的一次开源代码为例,教会你步入开源的世界. 1,首先登陆到htt ...

  2. 上传文件块client实现

    首先由内容阻止所有文件(块大小的约束),然后对于每一个chunk构造单独的一个UDP 数据报进行传输,在应用层的開始是自己定义的包头,有块号,块长度,块指纹等元数据信息,这些信息便于接收端可以按序正确 ...

  3. 于ubuntu配置hadoop当问题

    1. 构造ssh登录 我们并不需要改变/etc/ssh/sshd_config 2. 新hadoop用户,home下列不hadoop夹 创建使用下面的命令 useradd -m hadoop 3. n ...

  4. ListView单选的实现总结(转)

    今天在智能停车场项目中需要实现PullToRefreshListView的单选功能,考虑到分页,刷新等,以前的实现方式是采用自己维护一个集合保存选中位置的选中状态,但这个方式比较繁琐,今天采用了lis ...

  5. (大数据工程师学习路径)第一步 Linux 基础入门----正则表达式基础

    介绍 虽然我们这一节的标题是正则表达式,但实际这一节只是介绍grep,sed,awk这三个命令,而正则表达式作为这三个命令的一种使用方式(命令输出中可以包含正则表达式).正则表达式本身的内容很多,要把 ...

  6. 使用SeekBar办Android调色板

    1.接口布局xml代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" x ...

  7. 采用jquery的imgAreaSelect样品图像裁剪示范插件实现

    将用户上传的图片进行裁剪再保存是如今web2.0应用中经常处理的工作,如今借助jquery的imgareaselect插件再配合PHP的GD库就能够轻松的实现这个在曾经来说很棘手的功能. 我们来看看它 ...

  8. Mybatis 构造resultMap 搜sql

    映射配置文件 <!-- type:映射数据类型的实体类 id:resultMap的唯一标识 --> <resultMap type="person" id=&qu ...

  9. C#如何设置session过期时间

    1.操作系统  步骤:开始——〉管理工具——〉Internet信息服务(IIS)管理器——〉网站——〉默认网站——〉  右键“属性”——〉主目录——〉配置——〉选项——〉启用会话状态——〉会话超时(在 ...

  10. 第23章 访问者模式(Visitor Pattern)

    原文 第23章 访问者模式(Visitor Pattern) 访问者模式 导读:访问者模式是我个人认为所有行为模式中最为复杂的一种模式了,这个模式可能看一遍会看不懂,我也翻了好几个例子,依然不能很好的 ...