HashMap类的JDK实现剖析

1.结构

Map<K,V>是一个接口,这个接口内部还有一个接口,叫Entry<K,V>。HashMap中Entry接口的实现类是内部静态类:HashMap.Node,结构见下:

 static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
	/**/
}

HashMap类的结构见下:

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
	transient Node<K,V>[] table;
	transient Set<Map.Entry<K,V>> entrySet;
	transient int size;
	transient int modCount;
	int threshold;
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
	final float loadFactor;
	static final int TREEIFY_THRESHOLD = 8;
	/**/
}

size:map中元素的个数。

modCount:表示读以外的操作次数。用来检查并抛出ConcurrentModificationException。这是fast-fail思想。

TREEIFY_THRESHOLD: 若某个链表的长度大于此阀值,则将node转为TreeNode,即将链表转为红黑树。注意其他链表不受影响。

loadFactor:装填因子,与capacity搭配使用。

DEFAULT_INITIAL_CAPACITY:初始容量。capacity为数组(桶)的长度。capacity与loadfactor决定了扩容的threshold。

threshold: 初始=capacity*loadFactor。当size>threshold后,扩容,capacity与threshold都翻一倍。

2.写操作

V java.util.HashMap.put(K key, V value)
向map中添加元素,它会调用下面putVal(...)方法。
V java.util.HashMap.putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)
参数onlyIfAbsent:在为true的情况下,如果map中已经有这个key了,那么此次添加操作无效。
此函数的具体操作为:首先找到key所在的链表,table[i],这个下标i=(tab.length-1) & hash。如果table[i]=null,则新建node;否则遍历链表。若在遍历过程中遇到相等的key,按照onlyIfAbsent参数行事;若遇不到,在尾部新建node。

3.读操作

V java.util.HashMap.get(Object key)
根据key拿到value。它会调用getNode()方法,然后返回node的value。见下。
Node<K, V> java.util.HashMap.getNode(int hash, Object key)
先根据hashcode找到所在的链表。Node<K,V> first=table[(table.length-1) & hash]。然后遍历。

4.resize()扩容

Node<K, V>[] java.util.HashMap.resize()
扩容一倍。

首先申请新的数组,Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]。然后遍历旧数组的链表,分拆到新数组中。

5.treeify

JDK 1.8之前,HashMap是数组(桶)+链表实现,而1.8中作了大的变动,改为数组(桶)+链表+红黑树实现。
当链表长度超过阈值8时,将链表转换为红黑树,这样大大减少了查找时间。

时间: 2024-09-20 04:17:35

HashMap类的JDK实现剖析的相关文章

Java中Hashtable类与HashMap类的区别详解_java

Hashtable类 Hashtable继承Map接口,实现一个key-value映射的哈希表.任何非空(non-null)的对象都可作为key或者value. 添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数. Hashtable通过initial capacity和load factor两个参数调整性能.通常缺省的load factor 0.75较好地实现了时间和空间的均衡.增大load factor可以节省空间但相应的查找时间将增大,

JDK中常用包及其类和功能详细剖析

JDK所提供的所有标准Java类都存放在Java包中,如java.lang包中包含了运行Java必不可少的系统类.由于系统会自动将java.lang引入,所以不需要在源文件中用import语句来显示地引入这个包.另外,Java跪地过java.util和java.io是必须提供的标准包,在JDK中常用的包有以下几种: 1.java.lang:语言包 2.java.util:实用包 3.java.awt:抽象窗口工具包 4.javax.swing:轻量级的窗口工具包,这是目前使用最广泛的GUI程序设

使用JAR包中的类与JDK的rt.jar冲突的问题

问题描述 项目中遇到这样一个问题:使用的第三方JAR包中有一个整包(javax.management)与JDK的javax.management包重复了,但是具体实现却是不一样的,运行的时候第三方JAR包里的类试图调用自己提供的javax.management包里的类,但是JDK也提供了javax.management包,所以虚拟机优先调用了自己的javax.management里的类,于是就出错了.请问这个问题要怎么解决?因为这个原因项目已经停滞好久了,希望看到的大侠给解答一下,不甚感激!项目

UML类图关系全面剖析

UML的类图关系分为: 关联.聚合/组合.依赖.泛化(继承).而其中关联又分为双向关联.单向关联.自身关联:下面就让我们一起来看看这些关系究竟是什么,以及它们的区别在哪里. 1.关联 双向关联:C1-C2:指双方都知道对方的存在,都可以调用对方的公共属性和方法. 在GOF的设计模式书上是这样描述的:虽然在分析阶段这种关系是适用的,但我们觉得它对于描述设计模式内的类关系来说显得太抽象了,因为在设计阶段关联关系必须被映射为对象引用或指针.对象引用本身就是有向的,更适合表达我们所讨论的那种关系.所以这

javascript实现的HashMap类代码_javascript技巧

复制代码 代码如下: <script language = "javascript" > function HashMap() {     /**Map大小**/     var size = 0;     /**对象**/     var entry = new Object();     /**Map的存put方法**/     this.put = function(key, value) {         if (!this.containsKey(key)) {

java中HashMap类用法

  /* HashSet底层是采用HasMap实现的  HasMap保存的是  键值对 就跟 C++中 <map>容器类似 keySet() 返回键的视图  values() 返回值的视图 entrySet()  返回的每一个元素都是Map.Entry     Map中一个静态的接口接收键值对  */ import java.util.* ; class  Test { private static HashMap<String,String> hm=new HashMap<

四类ADSL故障的剖析和处理

在我们进行ADSL的使用中,常会遇到一些故障问题.很多问题看起来非常的"诡异",很多朋友不知如何解决.这里我们总结了几个ADSL故障的情况,帮助大家分析和解决. ADSL故障1.ADSL Modem上的"同步"灯不亮? ADSL Modem上的"同步"灯(一般是第二个灯)是ADSL最为重要的指示灯,它是判断ADSL能否通讯的第一步."同步"灯有几种状态":"同步"灯如果长亮,表明用户端的MODEM

Java集合---HashMap源码剖析

Java集合---HashMap源码剖析   一.HashMap概述二.HashMap的数据结构三.HashMap源码分析     1.关键属性     2.构造方法     3.存储数据     4.调整大小      5.数据读取                       6.HashMap的性能参数                       7.Fail-Fast机制   一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 

java-基础-hashmap剖析

hashmap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射HashMap实际上是一个"链表散列"的数据结构,即数组和链表的结合体.的顺序,特别是它不保证该顺序恒久不变.HashMap底层就是一个数组结构,数组中的每一项又是一个链表.当新建一个HashMap的时候,就会初始化一个数组. /** * The table, resized as necessary. Length MUST Alway