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. emmet的使用

    http://blog.wpjam.com/m/emmet-grammar/ 使用 Emmet 生成 HTML 的语法详解 开源程序 浏览:21537 2013年05月09日 文章目录[隐藏] 生成 ...

  2. Linux可信计算机制模块详细分析之核心文件分析(8)tpm.c核心代码注释(中)

    /*设置TPM命令格式*/ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, const char *desc) ...

  3. js中 checkTime()函数

    <html><head><script type="text/javascript">function startTime()//函数start ...

  4. Oracle 的字符集与乱码

    字符集问题一直叫人头疼,究其原因还是不能完全明白其运作原理. 在整个运行环节中,字符集在3个环节中发挥作用: 1.软件在操作系统上运作时的对用户的显示,此时采用操作系统定义的字符集进行显示.我们在系统 ...

  5. T-SQL 关闭数据库所有连接

    原文引用自: http://www.cnblogs.com/kissazi2/p/3462202.html 下面给出一种删除数据库活动连接的方式.将下面代码段中的"--修改一下"处 ...

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

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

  7. CSS清浮动处理(Clear与BFC)

    在CSS布局中float属性经常会被用到,但使用float属性后会使其在普通流中脱离父容器,让人很苦恼 1 浮动带来布局的便利,却也带来了新问题 <!doctype html> <h ...

  8. Java多线程--线程安全问题的相关研究

    在刚刚学线程的时候我们经常会碰到这么一个问题:模拟火车站售票窗口售票.代码如下: package cn.blogs.com.isole; /* 模拟火车站售票窗口售票,假设有50张余票 */ publ ...

  9. Tomcat服务器配置以及相关配置文件介绍

    摘自:http://blog.163.com/ny_lonely/blog/static/18892427320136925044357/ context.xml 文件   配置属性说明     用于 ...

  10. c++语言友元函数和成员函数对运算符重载

    #include<iostream> using namespace std; /******************************************/ /*use mem ...