Java集合之HashMap详解

Map类集合中的存储单位是Key-Value键值对,Map类使用一定的哈希算法形成比较均匀的哈希值作为Key,Value值挂在Key上。

一、Map类特点:

  1、Key不能重复,Value可重复

  2、Value可以是List、Map、Set类对象

  3、KV是否允许为null,以实现类约束为准

二、Map除提供增删改查外,还有三个Map特有方法。

  1、返回所有的Key

Set<K> keySet();

  返回Map类杜希昂中的Key的Set视图。

  2、返回所有value

Collection<V> values();

  返回Map类对象中的所有Value的Collection视图。

  3、返回所有K-V键值对

Set<Map.Entry<K, V>> entrySet();

  返回Map类对象中的K-V键值对的Set视图。

这些函数返回的视图支持清除操作(remove、clear),不支持修改和添加元素。

三、主要的Map类集合(图来自Java开发手册pdf)

Java集合之HashMap详解

Hashtable逐渐弃用,ConcurrentHashMap多线程比HashMap安全,但本文主要分析HashMap。

-------------------------------------------------------------------------------------------

HashMap

一、哈希类集合的三个基本存储概念

名称   说明  
table   存储所有节点数据的数组  
slot   哈希槽。即table[i]这个位置  
bucket   哈希桶。table[i]上所有元素形成的表或数的集合  

图示:

Java集合之HashMap详解

链表Node“Node是HashMap的一个静态内部类。

>//>Node是单向链表,实现了Map.Entry接口 >static >class Node<K,V> >implements Map.Entry<K,V> { >final >int hash; >final K key; V value; Node<K,V> next; >//>构造函数 Node(>int hash, K key, V value, Node<K,V> next) { >this.hash = hash; >this.key = key; >this.value = value; >this.next = next; } >//> getter and setter ... toString ... >public >final K getKey() { >return key; } >public >final V getValue() { >return value; } >public >final String toString() { >return key + "=" + value; } >public >final >int hashCode() { >return Objects.hashCode(key) ^ Objects.hashCode(value); } >public >final V setValue(V newValue) { V oldValue = value; value = newValue; >return oldValue; } >public >final >boolean equals(Object o) { >if (o == >this) >return >true; >if (o >instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; >if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) >return >true; } >return >false; } }

红黑树TreeNode:通过特定着色的旋转(左旋、右旋)来保证从根节点到叶子节点的最长路径不超过最短路径的2倍的二叉树,相比AVL树,更加高效的完成插入和删除操作后的自平衡调整。最坏运行时间为O(logN).

>static >final >class TreeNode<K,V> >extends LinkedHashMap.Entry<K,V> { TreeNode<K,V> parent; >//> red-black tree links TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; >//> needed to unlink next upon deletion >boolean red; TreeNode(>int hash, K key, V val, Node<K,V> next) { >super(hash, key, val, next); } >/**> * Returns root of tree containing this node. >*/ >final TreeNode<K,V> root() { >for (TreeNode<K,V> r = >this, p;;) { >if ((p = r.parent) == >null) >return r; r = p; } }

二、HashMap定义变量

>/**> * 默认初始容量16(必须是2的幂次方) >*/ >static >final >int DEFAULT_INITIAL_CAPACITY = 1 << 4; >/**> * 最大容量,2的30次方 >*/ >static >final >int MAXIMUM_CAPACITY = 1 << 30; >/**> * 默认加载因子,用来计算threshold >*/ >static >final >float DEFAULT_LOAD_FACTOR = 0.75f; >/**> * 链表转成树的阈值,当桶中链表长度大于8时转成树 threshold = capacity * loadFactor >*/ >static >final >int TREEIFY_THRESHOLD = 8; >/**> * 进行resize操作时,若桶中数量少于6则从树转成链表 >*/ >static >final >int UNTREEIFY_THRESHOLD = 6; >/**> * 桶中结构转化为红黑树对应的table的最小大小 当需要将解决 hash 冲突的链表转变为红黑树时, 需要判断下此时数组容量, 若是由于数组容量太小(小于 MIN_TREEIFY_CAPACITY ) 导致的 hash 冲突太多,则不进行链表转变为红黑树操作, 转为利用 resize() 函数对 hashMap 扩容 >*/ >static >final >int MIN_TREEIFY_CAPACITY = 64; >/**> 保存Node<K,V>节点的数组 该表在首次使用时初始化,并根据需要调整大小。 分配时, 长度始终是2的幂。 >*/ >transient Node<K,V>[] table; >/**> * 存放具体元素的集 >*/ >transient Set<Map.Entry<K,V>> entrySet; >/**> * 记录 hashMap 当前存储的元素的数量 >*/ >transient >int size; >/**> * 每次更改map结构的计数器 >*/ >transient >int modCount; >/**> * 临界值 当实际大小(容量*负载因子)超过临界值时,会进行扩容 >*/ >int threshold; >/**> * 负载因子 >*/ >final >float loadFactor;

默认容量:16   DEFAULT_INITIAL_CAPACITY = >1 << >4

自定义初始化容量:构造函数 ↓

Map容量一定为2的幂次。

默认加载因子:0.75  DEFAULT_LOAD_FACTOR = >0.75f

>自定义负载因子:构造函数 ↓

>桶中节点从链表转化为红黑树:节点数大于8

>桶中元素从红黑树返回为链表:节点数小于等于6

>threshold:临界值 = 容量×负载因子,当实际容量大于临界值,为了减小哈希冲突,进行扩容。

三、构造函数

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/a0b55bc306ddf8facc27dc66792cd4e4.html