集合知识点二:Map接口实现类

双列集合

双列集合图谱

Map接口

保存一组映射关系,键不可以重复,值可以重复

Map接口的实现类hashmap

底层结构
Jdk7:数组+链表
Jdk8:数组+链表+红黑树

结构数组类型初始化容量
Jdk7数组+链表Entry16
Jdk8数组+链表+红黑树Node0

Hashmap中维护了node类型的数组table,默认为null,无序

  1. 当创建对象时,将加载因子loadfactor初始化为0.75,其他成员保持默认值
  2. 添加元素时,相当于putval方法,需要先将待添加元素的哈希值算出来,并在数组中查找相应的索引处是否已存在元素,若不存在直接添加,如果该索引处已有元素,则判断是否相等,相等则直接覆盖,若不相等,则继续判断是否满足为树结构或链表结构,根据不同结果进行不同处理
  3. 如果需要扩容(resize),初次扩容,table的capacity为16,临界值threshold为12,其它次扩容table的capacity为当前的2倍,临界值threshold为当前的2倍
    临界值:数组容量*loadfactor
    扩容过程是非常消耗性能的因为要从新计算所有元素在新数组中所在的位置,所以我们尽量要提前预测元素个数
  4. 当链表中节点数>=8&&capacity>=64 则由链表结构变为树结构

Hashmap底层是一个特殊的数组,可以理解为该数组每个元素是一个链表

在这里插入图片描述

Jdk1.8之前的 数组+链表
在一个链表查询元素时,时间复杂度为O(n),效率很低

Jdk1.8之后,当在同一个hash值下的Entry数大于8时,就不再采用单链结构形式存储,转而采用红黑树存储数据
在这里插入图片描述

Jdk8之后 数组+链表+红黑树

当添加元素时put(),会先调用hashcode方法对待添加元素的key值进行hash运算,运算出结果确定待添加元素应该放在数组的那个位置,如果确定后发现该位置已有一个Entry,再通过equals方法对待添加元素的key和已有Entry的key进行比较,返回true待添加元素的value覆盖已有Entry的value,返回false待添加元素将于已有Entry形成Entry链表,而且新添加的元素位于链表头部
当查找元素时get(),会先调用hashcode方法对key进行hash运算,确定待查元素在数组中的哪个位置,当确定在数组中的那个位置后,jdk1.7之前是直接调用equals方法对该链表下的所有Entry的key进行比较查找(遍历)对应的Entry,找到返回value,时间复杂度为O(n),jdk1.8之后,需要判断数组该位置是否为红黑树结构,时间复杂度为O(log2N) 红黑树增删查时间复杂度均可记为O(log2N),N为红黑树元素个数

线程不安全:
ConcurrentModificationException 当在多线程的环境下对普通hashmap进行修改时,会报错,因为hashmap支持fast-fail机制,即hashmap每次修改,modcount就会+1,在迭代器初始化过程中会将modcount赋给迭代器的expectedModCount,在迭代过程中判断二者是否相等,不相等证明有线程修改了hashmap,立刻报ConcurrentModificationException异常

Linkedhashmap继承Hashmap1.7,但是不同的是底层在维护Entry的同时还维护了一个双向链表,使得在保存Entry数据的同时还保存了前一个元素before和后一个元素after的引用,从而在hash表的基础上又构成了一个双向链表 具有可预知的迭代顺序
不同步
实现了Fast-fail快速失败机制

Map接口的实现类Treemap sortedmap接口的实现类

底层结构是红黑树,一个二叉查找树,可以实现对添加元素key的自然排序和定制排序

 public class TreeMap<K,V>
     extends AbstractMap<K,V>
     implements NavigableMap<K,V>, Cloneable, java.io.Serializable

其中NavigableMap 是它实现的一个核心接口,NavigableMap接口继承了SortedMap(继承了Map)即一个支持排序的map,所以treemap才会支持排序

Treemap四个构造
无参 默认实现key的自然排序
有参 参数为comparator比较器 实现定制排序
有参 参数为map 实现key的自然排序
有参 参数为map ,comparator比较器 实现key的定制排序

自然排序:
要求待添加元素必须实现compareable接口并实现compareTo方法
定制排序:
要求待添加元素无序实现compareable接口,但创建Treemap对象时必须传入comparator的比较器,并实现compare方法(匿名内部类)

Map接口的实现类ConcurrentHashMap 同步hashmap

底层结构:双数组+链表 使用锁分离技术
Key唯一,值可以重复,不允许出现null键null值,无序的

在这里插入图片描述

Concurrenthashmap的数据结构可以这样理解:Concurrenthashmap底层是一个特殊的数组,数组中每一个元素都是hashtable(synchronized实现同步,fast-fail机制),hashtable的底层是一个Entry{}数组+链表(与hashmap类似唯一区别是线程安全),每一个Entry对象都是由K-V键值对组成的。这里就相当于把Concurrenthashmap分成了许多个hash表,每一个是一段即一个segment(就是一个hashtable)。这里每一个hashtable都有自己的锁,因为hashtable集合是线程安全的,这样只要并发发生在不同的segment上(即不同的hashtable上),各个段就可以并发进行

Concurrenthashmap是为了解决线程安全问题,hashmap是非同步的,当涉及到多线程且有读有写操作时,hashmap需要实现同步,随之带来的是将无法快速随机访问,此时就需要线程安全的map,此时我们通常的方案有hashtable或Collections.synchronizedMap(hashMap)经同步包装后的hashmap,二者的共性就是将会对整个hash表结构加上同步锁,这样当有一个线程对表进行操作时其它线程只能等待,性能不高,所以我们引入concurrenthashmap

Concurrenthashmap 定位一个元素需要进行两次hash操作,第一次定位到元素所在的segment,第二次定位到元素所在的链表的头部。所以concurrenthashmap相比较与hashmap,他的hash时间要长,但是能写操作的时候,只需要对元素所在的segment进行加锁即可,不影响其他元素的segment。所以在多线程性能上,concurrenthashmap要高于hashmap,在理想状态下,concurrenthashmap支持16个线程同时执行并发写操作(如果并发级别设置为16),及任意数量线程的读操作

Hashset 与 Hashmap区别
HashsetHashmap
实现接口SetMap
储存对象对象(实际也是K-V)键值对
添加元素方法.add().put()
索引计算(hashcode值)成员对象 计算键 计算
查找获取速度快 用键来查找
重复不允许重复键值不允许重复
同步不同步不同步
Hashtable和Hashmap比较

Hashtable类似于jdk1.7中的hashmap,最大区别在于它是线程安全

HashtableHashmap
同步同步不同步
基于类DictionaryAbstractmap基于map接口的实现
Null值问题Key value均不能为nullKey value 均可以为null
初始容量默认初始为11,扩容为old*2+1默认初始为16,old*2

Collections工具类 collection是集合接口 二者一定要区分开
Collections 是java.util包下的工具类,提供了一些列对集合进行操作的静态方法.

集合使用泛型的好处 ?
1、减少了编译警告
2、编译时检查类型,提高类型的安全性
3、大大减少了类型转换的次数,提高了效率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值