Bootstrap

Java集合(四)—— Map详解

Map接口

一、HashMap

public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable

1、HashMap概述

HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

2、HashMap的数据结构

在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体

3、HashMap的实现

HashMap 基于 Hash 算法实现的

  1. 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标
  2. 存储时,如果出现hash值相同的key,此时有两种情况。
    (1)如果key相同,则覆盖原始值;
    (2)如果key不同(出现冲突),则将当前的key-value放入链表中
  3. 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。
  4. 理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过8个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)。
3.1、JDK1.8之前的实现方法

JDK1.8之前采用的是拉链法。拉链法:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。
图片描述

3.2、JDK1.8之后的实现方法

相比于之前的版本,jdk1.8在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
在这里插入图片描述

3.3、红黑树

红黑树是一种特殊的二叉搜索树(又叫二叉排序树),其性质如下:

性质1、结点是红色或黑色。
性质2、根结点是黑色。
性质3、所有叶子都是黑色。(叶子是NIL结点)
性质4、每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
性质5、从任一节结点其每个叶子的所有路径都包含相同数目的黑色结点。(两条路径节点数在0到1倍之间)

查找、插入、删除的时间复杂度为O(log2 n),n为节点个数
注意:每一个插入的节点最初都是红色,后面经过旋转变色使自己达到红黑树的要求。

4、HashMap扩容机制

HashMap的默认初始容量为16,加载因子为0.75(即当元素个数超过容量长度的0.75倍 时,进行扩容)。
扩容增量为原容量的 1 倍,扩展后的新容量为原容量的2倍。

如 :HashSet的容量为16,一次扩容后是容量为32

4.1、为什么HashMap的长度是2的幂次方呢?
  • 取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作。也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;
  • 同时采用二进制位操作 &,相对于%能够提高运算效率。

二、HashTable

public class Hashtable<K,V>extends Dictionary<K,V>implements Map<K,V>, Cloneable, Serializable

HashTable的操作和HashMap相似,主要的区别在于HashTable实现了多线程安全,在方法上加上了synchronized关键字。

1、HashTable与HashMap的区别

HashMapHashTable
线程安全线程不安全,多线程下会造成并发冲突,但单线程下运行效率较高线程安全,但单线程环境效率也十分低,官方不推荐使用, 如果要保证多线程安全可以使用 ConcurrentHashMap代替
null key或者null valuenull 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。不允许key或者value有null值,否则会抛NullPointerException异常
容量和扩容默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。默认的初始大小为11,之后每次扩充,容量变为原来的2n+1
Hash映射hash算法通过非常规设计,将底层table长度设计为2的幂,使用位与运算代替取模运算,减少运算消耗hash算法首先使得hash值小于整型数最大值,再通过取模进行散射运算
底层结构数组+链表形成,在JDK1.8之后链表长度大于8时会转化为红黑树数组+链表
继承关系HashMap继承自AbstractMap类HashTable继承自Dictionary类

三、TreeMap

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

TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
TreeMap是线程非同步的。

;