HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是由于它是通过计算散列码来决定存储的位置。

HashMap中主要是通过key的hashCode来计算hash值的。仅仅要hashCode同样。计算出来的hash值就一样。假设存储的对象对多了,就有可能不同的对象所算出来的hash值是同样的,这就出现了所谓的hash冲突。

学过数据结构的同学都知道。解决hash冲突的方法有非常多,HashMap底层是通过链表来解决hash冲突的。

    HashMap事实上就是一个Entry数组。Entry对象中包括了键和值,当中next也是一个Entry对象。它就是用来处理hash冲突的。形成一个链表。数组的每一个元素都是一个单链表的头节点,链表是用来解决冲突的。假设不同的key映射到了数组的同一位置处,就将其放入单链表中。


 Hashtable 与 HashMap类似,可是主要有6点不同。

 1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个差别就像Vector和ArrayList一样。  
 2.HashTable不同意null值,key和value都不能够,HashMap同意null值,key和value都能够。HashMap同意key值仅仅能由一个null值,由于hashmap假设key值同样。新的key,
value将替代旧的。  
 3.HashTable有一个contains(Object value)功能和containsValue(Object value)功能一样。  
 4.HashTable使用Enumeration,HashMap使用Iterator。

 5.HashTable中hash数组默认大小是11,添加的方式是 old*2+1。HashMap中hash数组的默认大小是16,并且一定是2的指数。

1、HashTable的方法是同步的,HashMap未经同步
    Hashtable 提供的几个主要方法,包含 get(), put(), remove() 等。每一个方法本身都是 synchronized 的,会对整个对象进行加锁操作,不会出现两个线程同一时候对数据进行操作的情况。因此保证了线程安全性,可是也大大的减少了运行效率。

2、HashMap中hash数组的默认大小是16,并且一定是2的指数
  1. static int indexFor(int h, int length) {
  2. return h & (length-1);
  3. }
    将key的二次hash值。与长度减一进行与操作,这一步可谓经典,通常我们会用取模的方式来定位数组中的某个位置,我们首先想到的就是把hashcode对数组长度取模运算,这样一来,元素的分布相对来说是比較均匀的。

可是,“模”运算的消耗还是比較大的。能不能找一种更高速,消耗更小的方式那?hashMap用这样的方法,并且length即capacity的值。面capacity又是2的倍数,减1之后。表示成二进制就所有是1了。那么与所有为1的一个数进行与操作,速度会大大提升了。这就是为什么"capacity的值是2的倍数"


3、HashMap解决冲突的办法
    1)再哈希法
    2)拉链发
  1. public V put(K key, V value) {
  2. if (key == null)
  3. return putForNullKey(value);
  4. int hash = hash(key.hashCode());
  5. int i = indexFor(hash, table.length);
  6. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  7. Object k;
  8. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
  9. V oldValue = e.value;
  10. e.value = value;
  11. e.recordAccess(this);
  12. return oldValue;
  13. }
  14. }
  15. modCount++;
  16. addEntry(hash, key, value, i);
  17. return null;
  18. }
    依据key的hash值得到这个元素在数组中的位置(即下标),然后就能够把这个元素放到相应的位置中了。假设这个元素所在的位子上已经存放有其它元素了,那么在同一个位子上的元素将以链表的形式存放,新增加的放在链头。最先增加的放在链尾。从hashmap中get元素时。首先计算key的hashcode,找到数组中相应位置的某一元素,然后通过key的equals方法在相应位置的链表中找到须要的元素。

    调用int hash = hash(key.hashCode());这是hashmap的一个自己定义的hash,在key.hashCode()基础上进行二次hash。再哈希法可以解决开放地址法的聚集现象,可是却添加了时间复杂度。
  1. static int hash(int h) {
  2. h ^= (h >>> 20) ^ (h >>> 12);
  3. return h ^ (h >>> 7) ^ (h >>> 4);
  4. }
    改进传统的hash方法,并且尽量保证key的每一位都会影响到最后的hash值。以达到降低hash冲突的目的.

4、HashMap的构造函数
  1. if (initialCapacity < 0)
  2. throw new IllegalArgumentException("Illegal initial capacity: " +
  3. initialCapacity);
  4. if (initialCapacity > MAXIMUM_CAPACITY)
  5. initialCapacity = MAXIMUM_CAPACITY;
  6. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  7. throw new IllegalArgumentException("Illegal load factor: " +
  8. loadFactor);
  9. // Find a power of 2 >= initialCapacity
  10. int capacity = 1;
  11. while (capacity < initialCapacity)
  12. capacity <<= 1;
  13. this.loadFactor = loadFactor;
  14. threshold = (int)(capacity * loadFactor);
  15. table = new Entry[capacity];
  16. init();
  17. }
    loadFactor :载入因子,载入因子与HashMap resize有关。

默觉得0.75

    capacity:容器大小。默认值为16 其大小为上面所说的数据结构中数组的长度。

    table:即为上面数据结构图中。X方向的数组(transient Entry[] table;)
    threshold :resize的临界值,即当HashMap中无素个数达到该值时,HashMap就会调用其resize方法。又一次扩充大小。
    while (capacity < initialCapacity)
              capacity <<= 1;  
    这段代码说明什么:capacity的值是2的倍数,即使设置初始值是1000,hashmap也自己主动会将其设置为1024。

5、哈希表解决冲突的经常用法
    1)开放地址法
    2)拉链法
    3)再哈希法

拉链法的长处 ,与开放定址法相比,拉链法有例如以下几个长处: 
①拉链法处理冲突简单。且无堆积现象。即非同义词决不会发生冲突。因此平均查找长度较短。
②因为拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
③开放定址法为降低冲突,要求装填因子α较小。故当结点规模较大时会浪费非常多空间。

而拉链法中可取α≥1,且结点较大时,拉链法中添加的指针域可忽略不计,因此节省空间;

④在用拉链法构造的散列表中,删除结点的操作易于实现。仅仅要简单地删去链表上对应的结点就可以。而对开放地址法构造的散列表,删除结点不能简单地将被删结 点的空间置为空,否则将截断在它之后填人散列表的同义词结点的查找路径。这是由于各种开放地址法中,空地址单元(即开放地址)都是查找失败的条件。因此在
用开放地址法处理冲突的散列表上运行删除操作,仅仅能在被删结点上做删除标记。而不能真正删除结点。
拉链法的缺点 
拉链法的缺点是:指针须要额外的空间。故当结点规模较小时,开放定址法较为节省空间,而若将节省的指

HashMap源代码学习笔记的更多相关文章

  1. [Java] Map / HashMap - 源代码学习笔记

    Map 1. 用于关联 key 和 value 的对象,其中 key 与 key 之间不能重复. 2. 是一个接口,用来代替 Java 早期版本中的 Dictionary 抽象类. 3. 提供三种不同 ...

  2. [Java] LinkedList / Queue - 源代码学习笔记

    简单地画了下 LinkedList 的继承关系,如下图.只是画了关注的部分,并不是完整的关系图.本博文涉及的是 Queue, Deque, LinkedList 的源代码阅读笔记.关于 List 接口 ...

  3. jQuery源代码学习笔记_工具函数_noop/error/now/trim

    jQuery源代码学习笔记_工具函数_noop/error/now/trim jquery提供了一系列的工具函数,用于支持其运行,今天主要分析noop/error/now/trim这4个函数: 1.n ...

  4. [Java] List / ArrayList - 源代码学习笔记

    在阅读 List / ArrayList 源代码过程中,做了下面的笔记. LinkedList 的笔记较多,放到了另一篇博文 LinkedList / Queue- 源代码学习笔记 List List ...

  5. Java Jdk1.8 HashMap源代码阅读笔记二

    三.源代码阅读 3.元素包括containsKey(Object key) /** * Returns <tt>true</tt> if this map contains a ...

  6. jQuery源代码学习笔记:jQuery.fn.init(selector,context,rootjQuery)代码具体解释

    3.1 源代码 init: function( selector, context, rootjQuery ) { var match, elem, ret, doc; // Handle $(&qu ...

  7. jQuery源代码学习笔记:构造jQuery对象

    2.1源代码结构: (function( window, undefined ) { var jQuery = (function() { // 构建jQuery对象 var jQuery = fun ...

  8. [Java] TreeMap - 源代码学习笔记

    TreeMap 实现了 SortedMap 和 NavigableMap 接口,所有本文还会记录 SortedMap 和 NavigableMap 的阅读笔记. SortedMap 1. 排序的比较应 ...

  9. Angular源代码学习笔记-原创

    时间:2014年12月15日 14:15:10 /** * @license AngularJS v1.3.0-beta.15 * (c) 2010-2014 Google, Inc. http:// ...

随机推荐

  1. 编辑器sublime(转)摘自网络

    一.下载和安装 Sublime Text2是一款开源的软件,不需要注册即可使用(虽然没有注册会有弹窗,但是基本不影响使用). 下载地址:http://www.sublimetext.com/,请自行根 ...

  2. Mac下的Eclipse不能记住工作空间问题

    每次启动eclipse都要选择工作空间,即使你勾选了"选择这个作为默认"也不行. Eclipse版本 4.5, mac os版本10.12 找到这个目录下的config.ini文件 ...

  3. Fiddler-给手机设置代理并抓取https链接

    注:有两部分fiddler设置和手机端设置,且配置完成后,使用时确保PC和手机连接同一WiFi 设置方法如下: 1.上网搜索fiddler官方版下载,并安装完成后,开启fiddler 2.选择Tool ...

  4. python 配置opencv-python 接口

    anaconda2下配置opencv-python 接口,import cv2遇到no cv2 模块问题,解决办法是将cv2.so放到anaconda2/lib/python2.7/site-pack ...

  5. Android圆弧背景

    代码改变世界 Android圆弧背景 <?xml version="1.0" encoding="utf-8"?><shape xmlns:a ...

  6. 【Luogu】P3865ST表模板(ST表)

    题目链接 本来准备自己yy一个倍增来着,然而一看要求O1查询就怂了. ST表模板.放上代码. #include<cstdio> #include<cstdlib> #inclu ...

  7. POJ 2396 Budget ——有上下界的网络流

    给定矩阵的每行每列的和,和一些大于小于等于的限制.然后需要求出一组可行解. 上下界网络流. 大概的思想就是计算出每一个点他需要强行流入或者流出的量,然后建出超级源点和汇点,然后删除下界,就可以判断是否 ...

  8. 洛谷P3588 - [POI2015]Pustynia

    Portal Description 给定一个长度为\(n(n\leq10^5)\)的正整数序列\(\{a_n\}\),每个数都在\([1,10^9]\)范围内,告诉你其中\(s\)个数,并给出\(m ...

  9. 济南学习 Day 5 T1 am

    炮(cannon)[题目描述]众所周知,双炮叠叠将是中国象棋中很厉害的一招必杀技.炮吃子时必须隔一个棋子跳吃,即俗称“炮打隔子”. 炮跟炮显然不能在一起打起来,于是rly一天借来了许多许多的炮在棋盘上 ...

  10. POJ 2002 Squares [hash]

    Squares Time Limit: 3500MS   Memory Limit: 65536K Total Submissions: 16631   Accepted: 6328 Descript ...