HashMap:

内部基于数组和单向链表

重要的变量有:

Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;结点数组table中存储的元素为链表的头结点。

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;  数组table的初始化容量为16

int size;  size指HashMap中键值对的实际个数

final float loadFactor;  加载因子,默认0.75,

int threshold;  指阀值,当size大于threshold时,进行数组扩容(扩容后数组容量依然为2的次方数)

下图为HashMap的存储结构图,“position”,和“hello”的hash值对应的数组下标都为0,新插入的结点会存储在table数组中并通过next指针指向下一链表结点。

HashMap根据key获取value,插入键值对,判断key是否存在和根据key删除价值对的效率很高,时间复杂度为O(1)

因为大多数的key可以通过hash值一一对应,少部分会冲突,冲突相对较少,冲突的时候需要遍历链表

 public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key);  //根据键来获取相应结点 return null == entry ? null : entry.getValue();
}
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
} int hash = (key == null) ? 0 : hash(key);  //根据key计算hash值
for (Entry<K,V> e = table[indexFor(hash, table.length)];  //根据hash值和数组长度获取结点相应的数组下标
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))  //遍历链表获取根据hash值和key值找对应的结点
return e;
}
return null;
}
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
 public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);  //根据key计算hash值和数组下标
for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;    // 遍历链表,如果存在key值,则替换原来的values值
}
} modCount++;
addEntry(hash, key, value, i);  //不存在则新增结点,并存入table[i]中,新增结点会存储在数组中
return null;
}
 final Entry<K,V> removeEntryForKey(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev; while (e != null) {
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;  //删除节点后,将节点的后继结点存入数组或者将此结点的后继与前驱相连
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
} return e;
}

HashMap的遍历:

public static void main(String[] args) {

        HashMap<String, Integer> map=new HashMap<>();
map.put("1111", 1);
map.put("2222", 2);
map.put("3333", 3);
System.out.println(map.entrySet());
System.out.println(map.keySet());
Iterator<Entry<String, Integer>> it=map.entrySet().iterator();
while (it.hasNext()) {
System.out.println(it.next()); }
}

输出:

[2222=2, 1111=1, 3333=3]

[2222, 1111, 3333]

2222=2

1111=1

3333=3

深入HashMap的更多相关文章

  1. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  2. HashMap的工作原理

    HashMap的工作原理   HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...

  3. 计算机程序的思维逻辑 (40) - 剖析HashMap

    前面两节介绍了ArrayList和LinkedList,它们的一个共同特点是,查找元素的效率都比较低,都需要逐个进行比较,本节介绍HashMap,它的查找效率则要高的多,HashMap是什么?怎么用? ...

  4. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  5. 学习Redis你必须了解的数据结构——HashMap实现

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接博客园蜗牛 cnblogs.com\tdws . 首先提供一种获取hashCode的方法,是一种比较受欢迎的方式,该方法参照了一位园友的 ...

  6. HashMap与HashTable的区别

    HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...

  7. JDK1.8 HashMap 源码分析

    一.概述 以键值对的形式存储,是基于Map接口的实现,可以接收null的键值,不保证有序(比如插入顺序),存储着Entry(hash, key, value, next)对象. 二.示例 public ...

  8. HashMap 源码解析

    HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...

  9. java面试题——HashMap和Hashtable 的区别

    一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...

  10. 再谈HashMap

    HashMap是一个高效通用的数据结构,它在每一个Java程序中都随处可见.先来介绍些基础知识.你可能也知 道,HashMap使用key的hashCode()和equals()方法来将值划分到不同的桶 ...

随机推荐

  1. 我用ANDROID STUDIO开发,页面上总包这个警告,很烦!网上说是sdk版本问题,但是我是基于25开发的,最小版本也是19,有没有老司机啊?3克油

  2. PL/SQL异常获取

    1.no_data SET SERVEROUTPUT ON DECLARE pename EMP.ENAME % TYPE ; BEGIN SELECT ename INTO pename FROM ...

  3. Map工具系列-07-TFS变更集提取工具

    所有cs端工具集成了一个工具面板 -打开(IE) Map工具系列-01-Map代码生成工具说明 Map工具系列-02-数据迁移工具使用说明 Map工具系列-03-代码生成BySQl工具使用说明 Map ...

  4. Python json.dumps 特殊数据类型的自定义序列化操作

    场景描述: Python标准库中的json模块,集成了将数据序列化处理的功能:在使用json.dumps()方法序列化数据时候,如果目标数据中存在datetime数据类型,执行操作时, 会抛出异常:T ...

  5. ijkplayer导入AS时,出现more than one library with package name错误

    最近刚接触ijkplayer ,在ubuntu 中将ijkplayer编译后,导入Windows中AS时,出现以下错误,目前初步定为为包重名,但具体原因未定为到,麻烦有遇到这方面的朋友,给指导下,

  6. django创建新项目anministrator问题

    1.app中models的class可以通过migrations命令生成相应的数据表 2.此时并未写入数据库,migrate命令可以把相应的改动更新到数据库中 3.createsuperuser命令创 ...

  7. Swift-UIButton

    // let bt = UIButton(frame:CGRectMake(10,20,50,50)) let button = UIButton(frame:CGRectMake(10, 150, ...

  8. 利用Tomcat内置的servlet实现文件下载功能

    起因 最近博客所在的VPS挂了又要重装系统,又要重装各种软件. 以前我也经常更换VPS,每次更换都是各种坑爹事情..比如要下载java.下载tomcat.下载mysql..........以前每次我都 ...

  9. 室内定位系列(一)——WiFi位置指纹(译)

    原文:<Advanced Location-Based Technologies and Services>--chapter 2 WiFi Location Fingerprint 作者 ...

  10. MyBatis日志配置

    关于MyBatis的日志,其实MyBatis已经弄得很好了,你甚至都不用配置,只要导入了jar包,MyBatis就会自动寻找. 具体步骤 1.导入jar包,就是把下载MyBatis时,lib里的包复制 ...