HashMap底层原理小记

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

  首先HashMap 继承自AbstractMap(抽象类) 实现了Map接口。

  在new HashMap<K, V>()时,通过底层代码可以知道:

public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
}

  其中loadFactor为float型,指hash表的负载因子;DEFAULT_INITIAL_CAPACITY 为常量,是hash表的初始容量,初值为16;threshold为int型,是hash表的装载阈值,反应了hash表的装载程度。接下来就会初始化一个Entry类型的数组,初始容量为16;而其中table的类型Entry是Hashmap的一个静态内部类。

static class Entry<K,V> implements Map.Entry<K,V>,并且该类没有无参构造函数,
  Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }

 当使用hashMap.put(K,V)时, 

public V put(K key, V value) {
        if (key == null)				//判断键是否为null
            return putForNullKey(value);	//添加键为null的值
        int hash = hash(key.hashCode());	//计算二次计算key的hash值,避免冲突
        int i = indexFor(hash, table.length);	//根据hash值确定元素存放在表中的索引
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {	//定位到table中的位置后,取出当前的链表
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {	//判断key是否重复
                V oldValue = e.value;					//重复的时候返回重复key的value值
                e.value = value;
                e.recordAccess(this);				//这句的作用是什么不知道
                return oldValue;
            }
        }
        modCount++;				// modCount是不可被序列化的,具有可见性的,
//用来记录hashmap的修改次数
        addEntry(hash, key, value, i);		//添加一个键值对
        return null;
}

  

void addEntry(int hash, K key, V value, int bucketIndex) {
	Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
//当hash表的大小>=阈值时进行扩容,hash表的大小变为原来的两倍。
            resize(2 * table.length);
}

Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
//直接让原来table[bucketIndex]位置上的表头为新元素的next值,说明,每次插入元素都会在表位置中的表头。
            next = n;
            key = k;
            hash = h;
        }

void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {//当hash表的容量到达最大值时不再扩容
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);	//将原来hash表中的内容复制到新的hash表中
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }

  Hashmap中只允许有一个空键的原因:

  从代码中可以看出,当第二次添加空键的时候,会将原来null所对应的值覆盖,而且,空键所对应的key存放在表的第一个位置table[0].通过addEntry(0, null, value, 0),在第一次添加空键元素的时候,可以保证null所对应的元素在table[0]链表的表头。

private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

 

原文地址:https://www.cnblogs.com/wishboy/p/9529998.html

时间: 2024-10-10 12:22:18

HashMap底层原理小记的相关文章

HashMap底层原理分析(put、get方法)

1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那hash值就是相同的.当hash值相同时,就会出现hash冲突,HashMap通过链表来解决冲突. 原理图: 实例: import java.util.HashMap; import java.util.Map; ? public class HashMapTest { public static vo

面试官再问你 HashMap 底层原理,就把这篇文章甩给他看

前言 HashMap 源码和底层原理在现在面试中是必问的.因此,我们非常有必要搞清楚它的底层实现和思想,才能在面试中对答如流,跟面试官大战三百回合.文章较长,介绍了很多原理性的问题,希望对你有所帮助~ 目录 本篇文章主要包括以下内容: HashMap 的存储结构 常用变量说明,如加载因子等 HashMap 的四个构造函数 tableSizeFor()方法及作用 put()方法详解 hash()方法,以及避免哈希碰撞的原理 resize()扩容机制及原理 get()方法 为什么HashMap链表会

hashmap底层原理

从大的方向上来说,hashmap底层其实是采用数组+链表+红黑树的形式. 在数据插入过程中,随着数据量的增大,hashmap里通过数组扩容,链表转红黑树形式来存储数据的. 那么,数组扩容是什么时候进行扩容的呢? 其实,数组扩容是根据数组阈值来判定是否扩容,hashmap设定初始数组的个数默认是16个,而阈值则通过初始数组个数X默认加载因子0.75, 超过该阈值时,则链表(单链表)则转化为红黑树. hashmap的put过程: 在put的时候,是先根据存入hashmap的key计算出其hash值的

理解HashMap底层原理,一个简单的HashMap例子

package com.jl.testmap; /** * 自定义一个HashMap * @author JiangLai * */ public class MyHashMap<K,V> { Node<K,V>[] table;//位桶数组 int size;//存放键值对的个数 public MyHashMap() { table = new Node[16];//长度一般定义为2的整数次幂 } public void put(K key,V value) { //定义新的节点

HashMap的底层原理

简单说: 底层原理就是采用数组加链表: 两张图片很清晰地表明存储结构: 既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现: // 存储时: int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值 int index = hash % Entry[].length; Entry[index] = value; // 取值时: int hash = key.hashCode()

【1】Jdk1.8中的HashMap实现原理

HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变. 内部实现 HashMap的数据结构(字段) 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外.HashMap实际上是一个"链表散列"的数据结构,即数组和链表的结构,但是在jdk1.8里 加入了红黑

HashMap 实现原理

深入Java集合学习系列:HashMap的实现原理 参考文献 引用文献:深入Java集合学习系列:HashMap的实现原理,大部分参考这篇博客,只对其中进行稍微修改 自己曾经写过的:Hashmap实现原理 1. HashMap概述: HashMap是基于哈希表的Map接口的非同步实现(Hashtable跟HashMap很像,唯一的区别是Hashtalbe中的方法是线程安全的,也就是同步的).此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序

Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理

基于Lucene检索引擎我们开发了自己的全文检索系统,承担起后台PB级.万亿条数据记录的检索工作,这里向大家分享下Lucene底层原理研究和一些优化经验. 从两个方面介绍: 1. Lucene简介和索引原理 2. Lucene优化经验总结 1. Lucene简介和索引原理 该部分从三方面展开:Lucene简介.索引原理.Lucene索引实现. 1.1 Lucene简介 Lucene最初由鼎鼎大名Doug Cutting开发,2000年开源,现在也是开源全文检索方案的不二选择,它的特点概述起来就是

Jdk1.8中的HashMap实现原理

本文主要参考:美团点评技术团队 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变. HashMap的数据结构 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外.HashMap实际上是一个"链表散列"的数据结构,即数组和链表的结构,但是在jdk1.8