1、HashMap的数据结构(HashMap通过hashcode对其内容进行高速查找,是无序的)



数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。

数组 :数组的存储区是连续的,占用内存严重,故空间复杂度非常大。但数组的二分查找时间度小;数组的特点:寻址easy,插入和

删除困难。

链表 :链表的储存区离散。占用内存比較宽松。故空间复杂度非常小,但时间复杂度大;链表的特点:寻址困难,插入和删除easy。

哈希表

HashMap是由数组+链表组成。寻址easy,插入和删除easy。(存储单元数组Entry[],数组里面包括链表

HashMap事实上也是由一个线性的数组实现的。

所以能够理解为其存储数据的容器就是一个线性容器;

HashMap里面有一个内部静态类Entry,其重要的属性有key,value,next,从属性key,value 就能够非常明显的看出来 Entry就是

HashMap键值对实现的一个基础bean;也就是说HashMap的基础就是一个线性数组,这个数组就是Entry[]。Map里面的内容都保存

在Entry[]中;

    /**
* The table, resized as necessary. Length MUST Always be a power of two.
*/ transient Entry[] table;

2、HashMap的存取实现



2.1:存储

这里HashMap用了一个算法。

//存储时候:

int hash=key.hashCode(); //获取key的hashCode,这个值是一个固定的int值

int index=hash%Entry[].length。//获取数组下标:key的hash值对Entry数组长度进行取余

Entry[index]=value。

注意:假设两个key通过hash%Entry[].length得到的index同样。会不会覆盖?

是不会的。Entry类有一个next属性,作用是指向下一个Entry。打个例如, 第一个键值对A进来。通过计算其key的hash得到的

index=0。记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,如今怎么办?HashMap会这样做:B.next =

A,Entry[0] = B,假设又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方事实上存取了A,B,C三个键值对,他

们通过next这个属性链接在一起。

所以疑问不用操心。

也就是说Entry[]数组中存储的是最后插入的数据

	 public V put(K key, V value) {
if (key == null)
return putForNullKey(value); //null总是放在数组的第一个链表中
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
//遍历链表
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//假设key在链表中已存在,则替换为新value
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
} void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //參数e, 是Entry.next
//假设size超过threshold,则扩充table大小。再散列
if (size++ >= threshold)
resize(2 * table.length);
}

2.2:取值

获取key的hashcode指,通过hash值去hash%Entry[].length  获取Entry[hash%Entry[].length],定位到该数组元素之后,再遍历该元

素处的链表。

//取值时候:

int hash=key.hashCode();

int index =hash%Entry[].length;

return Entry[index];

     public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
//先定位到数组元素。再遍历该元素处的链表
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}

      当哈希表的容量超过默认容量时,必需要调整table的大小。

当容量达到最大值时,该方法Integer.MAX_VALUE返回。这时。就需要创建

一张表,将原来的表映射到新表中。



3、HashMap、HashTable和ConcurrentHashMap的线程安全问题

HashMap:线程不安全的。

HashTable:锁住整张hash表,让线程独占。hashMap同意为空。

通过分析Hashtable就知道,synchronized是针对整张Hash表的,即每次锁住整张表

让线程独占。安全的背后是巨大的浪费。

ConcurrentHashMap:一个更快的hashmap,它提供了好得多的并发性。多个读操作差点儿总能够并发地运行。

他是锁段(默认:把hash表分为16个

),在get,put,remove等操作中,ConcurrentHashMap仅仅锁定当前须要用到的段,仅仅有在求size的时候才锁定整张hash表。

HashMap的存储结构及原理的更多相关文章

  1. 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  2. 扰动函数和拉链法模拟HashMap的存储结构

    HashMap是Map接口下面的子孙,它对外是K,V结构存储的,而内部也着自己的存储结构,它的get操作是O(1)的时间复杂度,可以说是非常快的找到目录,而添加时,也是O(1),所以在键值存储里,它成 ...

  3. hbase操作(shell 命令,如建表,清空表,增删改查)以及 hbase表存储结构和原理

    两篇讲的不错文章 http://www.cnblogs.com/nexiyi/p/hbase_shell.html http://blog.csdn.net/u010967382/article/de ...

  4. HashMap的底层结构和原理

    http://youzhixueyuan.com/the-underlying-structure-and-principle-of-hashmap.html HashMap是Java程序员使用频率最 ...

  5. hbase 存储结构和原理

    HBase的表结构 建表时要指定的是:表名.列族 建表语句 create 'user_info', 'base_info', 'ext_info' 意思是新建一个表,名称是user_info,包含两个 ...

  6. Map实现之HashMap(结构及原理)(转)

    java.util包中的集合类包含 Java 中某些最常用的类.最常用的集合类是 List 和 Map.List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构 ...

  7. HashMap的存储原理

    HashMap是java中相当重要的数据结构,使用HashMap的场景非常之多,因此,了解HashMap实现的过程和原理,是非常有必要的,在一些面试中也会经常被问到.好了,我们赶紧来研究java内部是 ...

  8. HashMap底层结构、原理、扩容机制

    https://www.jianshu.com/p/c1b616ff1130 http://youzhixueyuan.com/the-underlying-structure-and-princip ...

  9. Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构

    Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构 1. 索引的分类1 1.1. 按照存储结构划分btree,hash,bitmap,fulltext1 1.2. 索引的类型  按查找 ...

随机推荐

  1. ios 绘制wav波形图

    最近研究了如何在iOS上绘制wav波形图.查了很多资料,都没能找到一个很完整的介绍,我这里总结一下一些经验. 首先需要了解wav的这3个重要指标:采样率.采样位数.声道数.下面以16KHz, 16Bi ...

  2. Flex中的折线图

    1.问题背景 在Flex中,制作一个折线图.而且给折线图的横轴和纵轴进行样式设置,详细实现过程例如以下: 2.实现实例 (1)设置横轴样式和数据绑定 <mx:horizontalAxis> ...

  3. jsPlumb开发入门教程(实现html5拖拽连线)

    jsPlumb是一个强大的JavaScript连线库,它可以将html中的元素用箭头.曲线.直线等连接起来,适用于开发Web上的图表.建模工具等.它同时支持jQuery+jQuery UI.MooTo ...

  4. Linux驱动开发常用头文件

    头文件目录中总共有32个.h头文件.其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个.这些头文件各自的功能如下: 1.主目录 <a.out.h> ...

  5. C#自定义List类

    代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespac ...

  6. XAML 概述

    我们将向 Windows 运行时应用开发人员介绍 XAML 语言和 XAML 概念,并介绍在使用 XAML 创建 Windows 运行时应用时,在 XAML 中声明对象和设置属性的不同方式. 什么是 ...

  7. C# DateTime的ToString()方法的使用

    Console.WriteLine("ToShortDateString:" + DateTime.Now.ToShortDateString()); Console.WriteL ...

  8. 服务器端操作Cookie[2]

    服务器端操作Cookie,主要注意会使用以下三个类: HttpCookie,HttpResponse,HttpRequest 关于HttpCookie: 属性 描述 例子 Domain 获取或设置与此 ...

  9. h5标签canvas关于getImageData跨域的问题

    h5标签canvas关于getImageData跨域的问题 在学习h5的时候,canvas标签中getImageData()报错:security error! 具体代码如下(chrome浏览器): ...

  10. PHP扩展开发(2) - VS2013环境搭建

    1. 安装VS2013 2. Cygwin安装 3. 下载Windows的PHP源码 4. 修改~/ext/ext_skel_win32.php     加上 $cygwin_path = 'c:\c ...