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. PHP 信号管理

    .note-content { font-family: "Helvetica Neue", Arial, "Hiragino Sans GB", STHeit ...

  2. js取当前周几

    纯javascript取当前周几 var dayNames = new Array("星期天","星期一","星期二","星期三& ...

  3. 首次接触nodejs

    嗯,2017年第一次接触nodejs ,也费了一些时间才终于将hello world正确运行出来. 下面说一下我的详情吧: 第一步:不用说,在https://nodejs.org/en/下载一款新的稳 ...

  4. Linux学习之CentOS(二十)--CentOS6.4下修改MySQL编码方法

    但是当我们在试图对数据库中的数据进行备份或者将sql文件导入到我们的数据库时可能就会碰到编码的问题,在windows下安装mysql时我们可以在安装的时候就选择好整个数据库的编码方式(通常设置成utf ...

  5. Navicat Premium 的常用功能

    1.快捷键 1.1. F8 快速回到当前对象列表 1.2. Ctrl + q 打开查询界面 1.3. Ctrl + d 快速修改当前的表结构 1.4. Ctrl + r 运行当前查询界面里面的 sql ...

  6. 【转】[教程]在 win7 / win8 下安装苹果系统 (懒人版)

    前言   这篇安装教程的素材在国庆就准备好了,但那时学习任务比较重,没有时间发帖,一直拖到现在.趁这个周末有空,赶紧写完它,希望能帮助一些景友. 论坛已经有不少安装教程,如果对这篇安装教程有疑问可以去 ...

  7. Python中print函数输出时的左右对齐问题

    为了将print函数输出的内容对齐,笔者在http://www.jb51.net/article/55768.htm中找到了左右对齐的方法.整理如下: 一.数值类型(int.float) #  %d. ...

  8. CSS基础总结

    CSS基础总结链接地址:http://segmentfault.com/a/1190000002773955

  9. Sublime Text 3 Plugin Better!

    Package Control Cmake ConvertUTF Markdown preview MarkdownEditing Marking Changed Rows

  10. .net mvc中的表单异步提交

    // // 摘要: // 将 <form> 开始标记写入响应. // // 参数: // ajaxHelper: // AJAX 帮助器. // // actionName: // 将处理 ...