hashmap

深入剖析HashMap应用原理

霸气de小男生 提交于 2019-12-14 22:08:21
Hashing(散列法或哈希法)的概念 散列法(Hashing)是一种将字符组成的字符串转换为固定长度(一般是更短长度)的数值或索引值的方法,称为散列法,也叫哈希法。由于通过更短的哈希值比用原始值进行数据库搜索更快,这种方法一般用来在数据库中建立索引并进行搜索,同时还用在各种解密算法中。 HashMap概念和底层结构 HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。HashMap储存的是键值对,HashMap很快。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。 数组:存储区间连续,占用内存严重,寻址容易,插入删除困难; 链表:存储区间离散,占用内存比较宽松,寻址困难,插入删除容易; Hashmap综合应用了这两种数据结构,实现了寻址容易,插入删除也容易。 hashMap的结构示意图如下: HashMap的基本存储原理以及存储内容的组成 基本原理:先声明一个下标范围比较大的数组来存储元素。另外设计一个哈希函数(也叫做散列函数)来获得每一个元素的Key(关键字)的函数值(即数组下标,hash值)相对应,数组存储的元素是一个Entry类,这个类有三个数据域,key、value(键值对),next(指向下一个Entry)。 例如,

jdk8 HashMap tableSizeFor

强颜欢笑 提交于 2019-12-14 21:43:27
今天读jdk8 HashMap源码,构造函数中 根据initialCapacity初始化threshold public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity);//大于initialCapacity的最小的2的幂 }   其中tableSizeFor 函数看的一脸懵,记录一下 /** * Returns a power of two size for the given

HashMap的常见问题

不打扰是莪最后的温柔 提交于 2019-12-14 21:20:24
关于HashMap的一些常见的问题,自己总结一下: 首选HashMap在jdk1.7和jdk1.8里面的实现是不同的,在jdk1.7中HashMap的底层实现是通过数组+链表的形式实现的,在jdk1.8中HashMap的底层是通过数组+链表+红黑树来实现的。 Question1: 数组链表是怎么切换的(1.7)? 答: 在put的时候采用hash(key)&(len-1)来计算数据存放的index,以此存放元素。当出现哈希冲突的时候,因为有限的数组长度,遭遇哈希冲突,此时就可以使用链表来存储哈希值相同但是值不同的对象。 Question2:Entry节点如何插入链表(1.7)? 答: Entry节点插入链表是使用头插法来实现的,主要的实现是通过其CreateEntry来实现的,Entry的构造方法中可以协助头插的顺利进行,使用头插法是考虑到热点数据的问题,当时的想法是最近插入的元素,最近也可能被使用,头插入的实现可以缩短链表查找元素的时间。 Question3:jdk1.8以后为什么改用尾插入? 答: 根据initialCapacity*LoadFactoor=capacity以后,如果插入的元素容量达到了capacity,此时会进行扩容,扩容操作按照源码中的写法,主要有两步:1.扩容一个新的Entry,容量为原来的两倍。2.进行Rehash操作,将原来的数据复制到新的Entry中

Java面试---HashMap的扩容过程

旧时模样 提交于 2019-12-14 18:21:31
1.如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办? 默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。这个值只可能在两个地方,一个是原下标的位置,另一种是在下标为<原下标+原容量>的位置 2.重新调整HashMap大小存在什么问题吗? 当重新调整HashMap大小的时候,确实存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。(多线程的环境下不使用HashMap) 为什么多线程会导致死循环,它是怎么发生的?   HashMap的容量是有限的。当经过多次元素插入,使得HashMap达到一定饱和度时,Key映射位置发生冲突的几率会逐渐提高。这时候,HashMap需要扩展它的长度,也就是  

Java HashMap工作原理

丶灬走出姿态 提交于 2019-12-14 16:36:41
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 内部存储 Java HashMap类实现了Map<K, V>接口。这个接口中的主要方法包括: V put(K key, V value) V get(Object key) V remove(Object key) Boolean containsKey(Object key) HashMap使用了一个内部类Entry<K, V>来存储数据。这个内部类是一个简单的键值对,并带有额外两个数据: 一个指向其他入口(译者注:引用对象)的引用,这样HashMap可以存储类似链接列表这样的对象。 一个用来代表键的哈希值, 存储这个值可以避免 HashMap在每次需要时都重新生成键所对应的哈希值。 下面是Entry<K, V>在Java 7下的一部分代码: 1 2 3 4 5 6 7 staticclassEntry<K,V>implementsMap.Entry<K,V> { finalK key; V value; Entry<K,V> next; inthash; … } HashMap将数据存储到多个单向Entry链表中(有时也被称为桶bucket或者容器orbins)。所有的列表都被注册到一个Entry数组中(Entry<K, V>[]数组),这个内部数组的默认长度是16。

Java HashMap工作原理【图文版】

て烟熏妆下的殇ゞ 提交于 2019-12-14 16:36:25
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 大部分Java开发者都在使用Map,特别是HashMap。HashMap是一种简单但强大的方式去存储和获取数据。但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.HashMap的大量源代码(包括Java 7 和Java 8),来深入理解这个基础的数据结构。在这篇文章中,我会解释java.util.HashMap的实现,描述Java 8实现中添加的新特性,并讨论性能、内存以及使用HashMap时的一些已知问题。 内部存储 Java HashMap类实现了Map<K, V>接口。这个接口中的主要方法包括: V put(K key, V value) V get(Object key) V remove(Object key) Boolean containsKey(Object key) HashMap使用了一个内部类Entry<K, V>来存储数据。这个内部类是一个简单的键值对,并带有额外两个数据: 一个指向其他入口(译者注:引用对象)的引用,这样HashMap可以存储类似链接列表这样的对象。 一个用来代表键的哈希值, 存储这个值可以避免 HashMap在每次需要时都重新生成键所对应的哈希值。 下面是Entry<K, V>在Java 7下的一部分代码: static class

HashMap默认容量的选择

风流意气都作罢 提交于 2019-12-14 12:53:43
集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生。 在日常开发中,我们经常会像如下方式以下创建一个HashMap: Map<String, String> map = new HashMap<String, String>(); 在创建HashMap时,我们没有指定容量,此时创建出来的HashMap的默认容量是多少呢?以及设置该默认容量呢? 1、什么是容量 在Java中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是: 寻址容易,插入和删除困难 ;而链表的特点是: 寻址困难,插入和删除容易 。HashMap就是将数组和链表组合在一起,发挥了两者的优势,我们可以将其理解为链表的数组。 在HashMap中,有两个比较容易混淆的关键字段: size和capacity ,这其中capacity就是Map的容量,而size我们称之为Map中的元素个数。 简单打个比方就更容易理解了:HashMap就是一个“桶”,那么容量(capacity)就是这个桶当前最多可以装多少元素,而元素个数(size)表示这个桶已经装了多少元素。 如下代码: Map<String, String> map = new HashMap<String, String>(); map.put("key", "value"); Class

HashMap-系列(面试)

爱⌒轻易说出口 提交于 2019-12-14 07:34:40
数据结构解析-HashMap 正文 一个婀娜多姿,穿着衬衣的小姐姐,拿着一个精致的小笔记本,径直走过来坐在我的面前。 看着眼前这个美丽的女人,心想这不会就是Java基础系列的面试官吧,真香。 不过看样子这么年轻应该问不出什么深度的吧,嘻嘻。(哦?是么) 小伙子,听前面的面试官说了,你Redis和消息队列都回答得不错,看来还是有点东西。 美丽迷人的面试官您好,您见笑了,全靠看了小编的《吊打面试官》系列,不然我还真的回答不上很多原本的知识盲区,他真的有点东西。 面试官心想:哦,吊打面试官是么,那今天我就让你知道,吊打这两个字怎么写的吧,年轻人啊,提前为你感到惋惜。 嗯嗯小帅比,虽然前面的技术栈没啥太大的瑕疵,不过未来很长的一段时间我会用一期期的基础教你做人的,你要准备好哟! 好了我们开始今天的面试吧,小伙子你了解数据结构中的HashMap么?能跟我聊聊他的结构和底层原理么? 切,这也太看不起我了吧,居然问这种低级问题,不过还是要好好回答。 嗯嗯面试官,我知道HashMap是我们非常常用的数据结构,由 数组和链表组合构成 的数据结构。 大概如下,数组里面每个地方都存了Key-Value这样的实例,在Java7叫Entry在Java8中叫Node。 因为他本身所有的位置都为null,在put插入的时候会根据key的hash去计算一个index值。 就比如我put(小编,520),我插入了为

Groovy transformer was like ignored

邮差的信 提交于 2019-12-14 04:08:17
问题 Good day, collegues. In my project i met some problem. In one of flows i have made two http_requests and then have parsed those responses with groovy transformer. First groovy script: Second groovy script: The first groovy script works fine. But the second script don't do anything. Like it was ignored. Both http_responses's structures are similar. Why the second groovy script can have been ignored? 回答1: Omg!( I am very sorry, this was my very stupid mistake. The reason is - 'break' must be in

How to avoid HashMap “ConcurrentModificationException” while manipulating `values()` and `put()` in concurrent threads?

拜拜、爱过 提交于 2019-12-14 03:41:45
问题 Code: I have a HashMap private Map<K, V> map = new HashMap<>(); One method will put K-V pair into it by calling put(K,V) . The other method wants to extract a set of random elements from its values: int size = map.size(); // size > 0 V[] value_array = map.values().toArray(new V[size]); Random rand = new Random(); int start = rand.nextInt(size); int end = rand.nextInt(size); // return value_array[start .. end - 1] The two methods are called in two different concurrent threads . Error: I got a