【Java】の基础——HashMap

来源:互联网 发布:windows 注册表修复 编辑:程序博客网 时间:2024/06/01 09:38

    • 哈希表
    • HashMap
      • Map
      • HashMap
    • HashTable
    • ConcurrentMap
    • TreeMap
    • LinkedHashMap

哈希表

说道HashMap,不得不提起哈希表(即散列表)这个存储结构。
平时我们在线性表(数组)中存储数据,查找一个数据需要逐个比较。那么有没有什么办法能更快查找到数据呢?
举个例子:

存储 22 41 53 46 29 14 01 这7个数存在下标0-10的数组中

我们可以事先定义一个规则(称为-哈希函数):

H(k) = key%p说白了就是对数组长度取余数。H(22)=22%11=0H(41)=41%11=8H(53)=53%11=9H(46)=46%11=2H(29)=29%11=7H(14)=14%11=3H(01)=01%11=1

存入数组结果是:
这里写图片描述
在查找的时候我们只要把key按照规则运算然后去查找就可以了,这就是哈希表。

但是,如果此时再存入 24,H(24)=24%11=2
我们会发现,根据规则查找到的位置2已经被人占用了,这种情况称为:哈希冲突。(本文就不从数据结构层面讨论解决哈希冲突的办法啦)

HashMap

Map

Map
提供了interface Entry

HashMap

首先我们看看HashMap的结构:
这里写图片描述

首先,它定义了一个Node:

    Node<K,V>{        int hash;        K key;        V value;        Node<K,V> next;    }

可以看出Node是一个链表的结点。

    Node<K,V>[] table;

而存储的主体table,则是Node的数组。

HashMap还有两个重要的值:

  • 加载因子(默认0.75):扩容的标准
  • 容量(初始值16):table的长度

我们可以结合HashMap创建的过程来看:

  • 首先默认创建一个长度为16的数组。
  • 当存入对象时,根据key的hashcode值对HashMap的容量求余数,决定该对象存放在数组中的位置。
    如果该位置已经有对象,则以链表的形式存储(jdk1.8之前用头插法,1.8用尾插法)。
  • 当然,如果table数组已经占满75%(根据加载因子0.75),那么就对哈希表进行扩充,这个过程称为重新散列,将其容量扩大一倍。
  • 此外,在jdk1.8中,如果一个链表节点数大于8,那么将其转化为红黑树进行存储。

HashTable

HashMap是HashTable的轻量级实现,HashMap 不是线程安全
HashTable的方法都加了同步锁,因此是线程安全的。相应的,它的效率也较低。

ConcurrentMap

ConcurrentMap是线程安全的Map。
ConcurrentHashMap的同步机制和HashTable不同,它不是加synchronized关键字,而是基于lock操作的,这样的目的是保证同步的时候,锁住的不是整个对象
一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

TreeMap

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

LinkedHashMap

LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

0 0
原创粉丝点击