深入HashMap
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的更多相关文章
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- HashMap的工作原理
HashMap的工作原理 HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...
- 计算机程序的思维逻辑 (40) - 剖析HashMap
前面两节介绍了ArrayList和LinkedList,它们的一个共同特点是,查找元素的效率都比较低,都需要逐个进行比较,本节介绍HashMap,它的查找效率则要高的多,HashMap是什么?怎么用? ...
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- 学习Redis你必须了解的数据结构——HashMap实现
本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接博客园蜗牛 cnblogs.com\tdws . 首先提供一种获取hashCode的方法,是一种比较受欢迎的方式,该方法参照了一位园友的 ...
- HashMap与HashTable的区别
HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...
- JDK1.8 HashMap 源码分析
一.概述 以键值对的形式存储,是基于Map接口的实现,可以接收null的键值,不保证有序(比如插入顺序),存储着Entry(hash, key, value, next)对象. 二.示例 public ...
- HashMap 源码解析
HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...
- java面试题——HashMap和Hashtable 的区别
一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...
- 再谈HashMap
HashMap是一个高效通用的数据结构,它在每一个Java程序中都随处可见.先来介绍些基础知识.你可能也知 道,HashMap使用key的hashCode()和equals()方法来将值划分到不同的桶 ...
随机推荐
- Jetson ARM SeetaFace编译
SeetaFace简介 SeetaFace依赖于OpenCV,对于Tegra on Ubuntu,Nvidia提供libopencv4tegra并且可以使用Cuda加速. 准备工作 1.阅读OpenC ...
- MySQL的InnoDB索引原理详解
摘要 本篇介绍下Mysql的InnoDB索引相关知识,从各种树到索引原理到存储的细节. InnoDB是Mysql的默认存储引擎(Mysql5.5.5之前是MyISAM,文档).本着高效学习的目的,本篇 ...
- 给zabbix穿一件漂亮的衣服
推荐给zabbix穿上一件漂亮的衣服,安装Grafana推荐连接:http://www.myexception.cn/software-testing/2008870.html yum install ...
- IntelliJ IDEA 15,16 win 7 64位安装包以及注册码 百度云盘
不知道发出来,有用没有,要是官网下载不了的话,可以用我的这个哦,虽然不是最新的. ideaIU-162.1447.21 ideaIU-15.0.2 win7 64系统的安装包 链接:http://p ...
- 如何查看编译安装的lnmp环境各自的配置参数
安装好后如何查看mysql/apache/nginx/php安装参数 查看mysql编译参数: cat /usr/local/mysql/bin/mysqlbug | grep CONFIGURE ...
- Linux开机自动登录(文本模式)
• Linux系统启动登录过程 以RedHat/CentOS为例,Linux系统Level3模式下从启动到登录的整个过程大致如下: 1> 加载BIOS信息:包含了CPU/显卡/内存/硬盘/网卡等 ...
- .net 面试基础题
Reference Link:http://www.yjbys.com/bbs/326026.html const关键字用来声明编译时常量,readonly用来声明运行时常量 密封类不能同时为抽象类 ...
- virtualBox上虚拟机和主机互联{}
VirtualBox实现内外网络互访问的配置 环境: 宿主机操作系统 Windows XP sp3 虚拟机软件 VirtualBo ...
- linux centos 6.5下安装nodejs
1.将文件下载或拷贝至/usr/local/src目录下,可使用xshell工具上传文件 2.解压缩文件: tar xvf /usr/local/src/node-v6.9.2-linux-x64 3 ...
- Yii2 ActiveRecord save失败
当给AR写beforeSave方法时,注意返回true还是false.如果没有返回值,或者返回false,那么就不会存入数据库.如下 晚上写代码的时候beforeSave忘了返回true,导致无法存入 ...