集合类的架构图:

HashMap

  • 内部维护一个链表数组做哈希表,默认大小为16,最大值可以为2^30,默认负载因子0.75。
  • 可以通过构造方法指定初始大小和负载因子,当键值对个数大于等于临界值threshold(数组当前大小和负载因子的乘积)时对数组进行扩容,扩容策略为当前数组大小乘以2。
  • 数组的每一项都是一个链表,链表的每个结点(静态内部类Entry)都是键值对,并缓存了key的hash值。
  • key 和value都可以为null,key为null时结点存储在hash表数组下标为0的位置。

put过程:

    public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
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;
}
  • 通过key的hashcode计算出一个内部的hash值,然后用这个hash值对哈希表大小取余(算法为h & (length-1),此处可以体现hash表length扩容策略为指数方式的优势)定位到哈希表的位置,然后遍历该位置的链表,当遇到相等的key时,替换原来的value并将原来的value返回
  • 如果没找着key相同的记录,就在相应位置添加新的链表结点,并将原来该位置的链表链接到此节点后,此节点作为头结点,当size大于阈值,则扩容到原来数组大小的两倍

HashMap不是线程安全的,多线程环境下可能造成死循环(对hash表扩容后transfer数据时发生)或者丢失数据(hash冲突后添加新节点到链表时发生)。

HashSet
HashSet通过内嵌一个HashMap对象的方式来实现,通过HashMap的key来存储,value都是相同的一个空Object()对象。与HashMap一样,要求需要存储的key实现hashcode和equals方法,且与HashMap具备同样的初始大小和扩容策略。

TreeMap

红黑树:一种大致平衡的二叉查找树,大致平衡是为了在保持较高检索效率的同时还不需要频繁调整,从而保持了统计上的性能。

  • TreeMap内部使用了红黑树来实现,维护其根节点,每个key-value都内嵌于其中一个节点(Entry),同时Entry还具有left、right、parent以及color属性用以维持其树形结构。
  • 结点之间按key有序,需要key实现comparable接口或者在构造方法中传入一个比较器comparator。
  • 迭代时按key排序,保存时会使用key的比较结果对key进行排重,只要比较结果相同就会被认为是同一份,此时保存的key值为第一次put的key,value为第二次put进去的value
  • 通过key get时,搜索二叉查找树,找到匹配的返回其value,找不到返回null
  • 通过value获取时,遍历所有节点搜索
  • TreeMap实现了SortedMap和NavigableMap接口,可以方便的根据键的顺序进行查找,如第一个、最后一个、某一范围的键、邻近键等。
  • 根据键保存、查找、删除的效率比较高,为O(h),h为树的高度,在树平衡的情况下,h为log2(N),N为节点数。
  • TreeSet
  • 内部持有一个TreeMap,类似HashSet,没有重复元素,添加删除判断元素是否存在效率较高,为O(log2N),N为元素个数
  • 有序,可以方便的根据顺序进行查找和操作,如第一个,最后一个,某一取值范围,某一值的近邻元素。

LinkedHashMap

  • LinkedHashMap是HashMap的子类,内部有一个双向链表维护键值对的顺序,每个键值对既位于哈希表中,也位于这个双向链表中。
  • 双向链表的结点LinkedHashMap.Entry继承自HashMap.Entry,添加了before和after两个引用参数,同时重写了HashMap.Entry的recordAccess和recordRemoval方法以维护和hash表中节点的关系。
  • LinkedHashMap支持两种顺序,一种是插入顺序,另一种是访问顺序,默认情况下按插入有序,构造方法中accessOrder设为true的时候按访问顺序,可以用来实现LRU缓存(最近最少使用)

LinkedHashSet
LinkedHashMap也有一个对应的Set接口的实现类LinkedHashSet。LinkedHashSet是HashSet的子类,但它内部的Map的实现类是LinkedHashMap,所以它也可以保持插入顺序

EnumMap
内部使用数组实现,构造方法需要传入类型信息。允许值为null,为了区分null和没有值,用一个静态全局唯一的new Integer(0)值来作为没有值

EnumSet
内部使用位向量实现,是一个抽象类,不能直接通过new关键字来新建,必须使用类似于noneOf的其他工厂方法方法创建一个指定枚举类型的set,实际创建的对象是EnumSet的子类RegularEnumSet或JumboEnumSet。

具体子类类型根据传入的枚举类型枚举值的数量来决定:

  • 小于等于64返回维护一个long变量(long为64位)作为位向量的子类RegularEnumSet
  • 大于64返回一个内部维护long数组作为位向量的子类JumboEnumSet

下面是一些工厂方法:

// 初始集合包括指定枚举类型的所有枚举值
<E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
// 初始集合包括枚举值中指定范围的元素
<E extends Enum<E>> EnumSet<E> range(E from, E to)
// 初始集合包括指定集合的补集
<E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s)
// 初始集合包括参数中的所有元素
<E extends Enum<E>> EnumSet<E> of(E e)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4)
<E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5)
<E extends Enum<E>> EnumSet<E> of(E first, E... rest)
// 初始集合包括参数容器中的所有元素
<E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s)
<E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)

Java集合总结(二):Map和Set的更多相关文章

  1. Java 集合系列 15 Map总结

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  2. Java集合框架之Map接口浅析

    Java集合框架之Map接口浅析 一.Map接口综述: 1.1java.util.Map<k, v>简介 位于java.util包下的Map接口,是Java集合框架的重要成员,它是和Col ...

  3. Java集合框架之map

    Java集合框架之map. Map的主要实现类有HashMap,LinkedHashMap,TreeMap,等等.具体可参阅API文档. 其中HashMap是无序排序. LinkedHashMap是自 ...

  4. Java 集合系列 08 Map架构

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  5. (Set, Map, Collections工具类)JAVA集合框架二

    Java集合框架部分细节总结二 Set 实现类:HashSet,TreeSet HashSet 基于HashCode计算元素存放位置,当计算得出哈希码相同时,会调用equals判断是否相同,相同则拒绝 ...

  6. 【JAVA集合框架之Map】

    一.概述.1.Map是一种接口,在JAVA集合框架中是以一种非常重要的集合.2.Map一次添加一对元素,所以又称为“双列集合”(Collection一次添加一个元素,所以又称为“单列集合”)3.Map ...

  7. 【由浅入深理解java集合】(二)——集合 Set

    上一篇文章介绍了Set集合的通用知识.Set集合中包含了三个比较重要的实现类:HashSet.TreeSet和EnumSet.本篇文章将重点介绍这三个类. 一.HashSet类 HashSet简介 H ...

  8. Java集合框架中Map接口的使用

    在我们常用的Java集合框架接口中,除了前面说过的Collection接口以及他的根接口List接口和Set接口的使用,Map接口也是一个经常使用的接口,和Collection接口不同,Map接口并不 ...

  9. java集合框架07——Map架构与源代码分析

    前几节我们对Collection以及Collection中的List部分进行了分析,Collection中还有个Set,因为Set是基于Map实现的,所以这里我们先分析Map,后面章节再继续学习Set ...

  10. 「 深入浅出 」java集合Collection和Map

    本系列文章主要对java集合的框架进行一个深入浅出的介绍,使大家对java集合有个深入的理解. 本篇文章主要具体介绍了Collection接口,Map接口以及Collection接口的三个子接口Set ...

随机推荐

  1. Fabric中的节点类型

    在Fabric中,尽管所有对等节点/peer都是相同的,但它们可以根据网络的配置方式承担多个角色:(①②是主要的节点类型) ①提交节点: 通道中的每个对等节点都是一个提交节点.它们接收生成的交易区块, ...

  2. SVN操作出现locked错误解决办法

    SVN操作出现locked错误解决办法:在SVN中执行 commit 操作时,在更新过程中,中断过,或者因为其他原因导致SVN 出现 locked 异常. 解决办法:1. 选中出现异常的文件,右键 - ...

  3. Qt实现艺术字效果

    Qt实现艺术字效果,通常有三种方式,一种是通过绘制机制,另外一种是使用样式表,最后一种是通过图片代替,本次介绍使用绘制来实现艺术字效果. 代码如下(分两种实现): 第一种: QPainter pain ...

  4. ckplayer获取播放时长一

    <div id="a1"></div> <div id="nowTime"></div> <script ...

  5. (十六)客户端验证与struts2中的服务器端验证

    一.客户端验证: 即用javaScript来验证. <%@ page language="java" contentType="text/html; charset ...

  6. SpringMVC 出现 406(Not Acceptable)

    首先,需要清楚,http state 406代表什么意思: 406是HTTP协议状态码的一种,表示无法使用请求的特性来响应请求的网页.一般指客户端浏览器不接受所请求页面的MIME类型. 出现这样的错误 ...

  7. ASP.NET Core本身已经集成了一个轻量级的IOC容器

    1.services.AddTransient<IApplicationService,ApplicationService>//服务在每次请求时被创建,它最好被用于轻量级无状态服务(如我 ...

  8. reactnative中FlatList上拉加载更多的解决办法

    项目app中用到了list滚动加载,把List做了下对比发现FlatList比较适合自己的项目,但是在实际运用中 onEndReached方法需要给定 onEndReachedThreshold的高度 ...

  9. 使用Java Executor框架实现多线程

    本文将涵盖两个主题: 通过实现Callable接口创建线程 在Java中使用Executor框架 实现Callable接口 为了创建一段可以在线程中运行的代码,我们创建了一个类,然后实现了Callab ...

  10. Linux学习笔记:cut命令

    基础 功能:文件内容查看,显示行中指定部分,删除文件中指定字段.cut 命令用于显示每行从开头算起 a - b 的文字. 语法: cut [-bn] [file.txt] cut [-c] [file ...