从源码中分析HashMap的get跟put方法

话不多说直接上代码

put

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }


final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

#get

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

        final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

问题所在

对于2个方法的逻辑看的不是很懂虽然大概知道,先通过hash去找,如果找不到一样的hash就新建Entry,如果找到一样的判断key是否也相等,如果相等则覆盖value,如果不想等说明是key不相同但是hash相同,那么生成Entry赋值给父的next。本人的逻辑理解是这样的,但是对源码还是看不懂。
1. ,put方法中

if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }

这段逻辑不是很懂。

2.get方法中

if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);

这一段不是很理解,求解释。越详细越好。在写笔记看到这里突然卡住了,求支招。哈哈哈。

4个回答

  1. if ((tab = table) == null || (n = tab.length) == 0)
    1. n = (tab = resize()).length;
    2. if ((p = tab[i = (n - 1) & hash]) == null)
    3. tab[i] = newNode(hash, key, value, null);
    4. else {
    5. Node e; K k;
    6. if (p.hash == hash &&
    7. ((k = p.key) == key || (key != null && key.equals(k))))
    8. e = p;
    9. else if (p instanceof TreeNode)
    10. e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
    11. else {
    12. for (int binCount = 0; ; ++binCount) {
    13. if ((e = p.next) == null) {
    14. p.next = newNode(hash, key, value, null);
    15. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
    16. treeifyBin(tab, hash);
    17. break;
    18. }
    19. if (e.hash == hash &&
    20. ((k = e.key) == key || (key != null && key.equals(k))))
    21. break;
    22. p = e;
    23. }
    24. } 解读这一段源码:
  2. java1.8中,map的结构是由Node[] + 链表组成的,和之前的主要区别是,链表部分,当超过8个元素会转成TreeNode对象,由TreeBin封装,也就是链表转换为树形结构便于存储和查找。不是线程安全类,但是如果多线程操作会报出ConCurrentxxxException。

下面按行数来说:
1. 如果当前Node[] 为null 或者 Node数组元素个数为0 执行下面一行代码(省略大括号)
2. resize() 方法返回一个扩容后的Node[],扩容的机制为所需容量的两倍,是原有的1.5倍,这个计算是由负载因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; 来决定的(具体的可以看一下resize()方法,如果有困难我们再讨论一次)。 Node数组元素个数n 赋值为扩容后的长度。
4. 「 (n - 1) & hash] 」定位数组下标位置的经典算法,你可以自己写一个main方法来做几个实验。n=16的话,计算结果肯定在0~15之间。p为计算后取到的一个Node节点 判断是否为null (if else 省略大括号)
5. 如果上述判断为true,那么当前节点赋值为一个新建节点 newNode(x,x,x,x); 这个不用说吧。也是一个经典数据结构。
6. 如果4 中判断结果为false,证明当前下标为i的位置存在节点,那么进行下列操作。
7、8、9. 如果当前node节点的hash 和 节点中key属性值 双等或值等(也就是进行新旧值替换),则将当前节点赋值给e。
10、11. 如果当前节点为TreeNode节点,则将当前操作元素添加到TreeNode[]中(图中,单独的hash,key,value都是当前操作元素的值)。
12. 如果上述都不成立,直接执行下列代码(到这步的意思是,不会是覆盖操作,当前节点也不是treeNode,只能是将当前节点拼接在列表末端)。
13-23. 这是一个看似无限循环的算法,这有几个退出点,按顺序来,第一个break,代表找到了列表末端,把当前元素添加到末端即可。第二个break,是找到新旧值覆盖的元素,进行替换。

14行为常规列表遍历。
15行为如果找到最后一个元素了,直接新建元素,将最后一个元素与新元素逻辑关联。
16行 判断当前个数,是否大于或者等于7,如果是,则将列表转化为TreeBin包装类,其实列表转树的界限是8,但是数组下标是从0开始,所以是TREEIFY_THRESHOLD - 1。
17行就是转化方法了。

用有道笔记纯手打!

qq_27156775
私奔Sven 到了第8个,不是让链表过长,这部分是jdk8做的优化,增快查询效率等。其他理解没问题。记住一点,他初始化的size不是16,而是0,也就是{},当有写操作的时候才会赋值16(也就是1<<4),这个你可以看源码来理解。
一年多之前 回复
StackTc
StackTc 回复私奔Sven: 看了下,我说下我的理解,1:如果数组为空直接赋值 2:如果hash跟key都一样覆盖 3:如果hash值一样key不一样,创建链表。到了第8个的时候由于不让链表过长。就以树的形势存储数据,
一年多之前 回复
qq_27156775
私奔Sven 这些都是经典,以jdk8为主,7也要看,因为你要知道它什么这么优化和怎么优化的。
一年多之前 回复
StackTc
StackTc 回复qq_27156775: 晚上我回去看一下1.8源码,再回复你,还有问下,看源码建议看1.7还是1.8?
一年多之前 回复
qq_27156775
私奔Sven 首先你要知道,jdk8之后,hashmap中,数据结构是Node[]+(链表|树),Node[]肯定是不会改变的了,那什么时候用链表,什么时候是树呢?他们有个临界点,8,这个数字我在回答里也说过,你在源码里也能找到。知道这个8了,我们看下怎么转化的,首先,数组中的一个元素,他是从链表就够开始构造的,也就是说,你连续put相同的(lenght-1)&hash的值,当个数小于8的时候,用的都是链表,也是就是node.next=new Node()形式,当个数大于等8的时候,将链表转化为TreeNode形式,p instenceof NodeTree 就是用来判断,让数组元素,是链表还是树,如果返回时true,那么,当前元素下的结构已经是树,就用树的方式将当前操作的对象加入到树中,反之还是链表,将当前操作的对象,加入到链表末尾,加入完成之后,判断是否需要转化为树结构,判断条件是什么呢,就是那个8.
一年多之前 回复
StackTc
StackTc 还是不是很理解TreeNode 这玩意,我目前的理解是newNode为增加一个链表数据或者节点,10.11.12行代码 还不是很理解
一年多之前 回复
qq_27156775
私奔Sven 对的,jdk8还优化了扩容相关的。
一年多之前 回复
StackTc
StackTc 回复qq_27156775: 这是jdk1.8新加的?我看1.7都是Entry链表形式的
一年多之前 回复
qq_27156775
私奔Sven 回复StackTc: 我提到过,当链表的size大于8.下标大于等于7的时候就要转换为TreeNode对象进行存储,在map中,它托管给了TreeBin,所以‘p instanceof TreeNode’ 这个就是判断,数组中的这个元素,是链表还是TreeNode存储,或者说结构。如果是TreeNode,直接采用putTreeVal()方法将当前操作的对象插入。有不懂的可以继续问,有错误,欢迎提出
一年多之前 回复
StackTc
StackTc else if (p instanceof TreeNode) e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
一年多之前 回复
StackTc
StackTc else if (p instanceof TreeNode) 这句话可以分析一波吗
一年多之前 回复
qq_27156775
私奔Sven 如有不对,欢迎指出~
一年多之前 回复

首先你要知道HashMap最基本的原理,就是把要存储的所有键做Hash,映射到一个数组中去。

但是有可能两个甚至更多的键映射到了同一个位置,因此HashMap需要解决的最核心的问题就来了,就是“哈希冲突”。

jdk7及以前的做法比较简单,如果出现哈希冲突,就在出现冲突的数组位置上创建一个链表,存储所有冲突的对象。这样的问题是,如果冲突的对象很多,那么这个链表会很长,会导致HashMap的性能大大下降。

因此在jdk8发布的时候做了一个优化,在冲突较少的时候依然使用链表,冲突较多的时候,就把链表转换成一棵红黑树。

这也就是你在看代码的时候看到的Node(链表节点)和TreeNode(红黑树节点)。

yizishou
yizishou 回复StackTc: 恩,他说的更具体
一年多之前 回复
StackTc
StackTc 感谢,你说的很正确,但是我还是打算把分给楼上。
一年多之前 回复

还有哈希表 为什么比数据查找速度快

StackTc
StackTc 回复whb3299065: 谢谢
一年多之前 回复
whb3299065
whb3299065 if ((p = tab[i = (n - 1) & hash]) == null)看这句其中i = (n - 1) & hash ,就是计算到哈希值对应的位置,可以看到,它并没有对表结构进行遍历,而是通过计算可以直接得到位置在,只有在该位置被其他元素占用后才会遍历查找,效率是O(1)-O(N)之间,大部分都可以在O(1)的复杂度内找到
一年多之前 回复

还有问下,为什么别人的博客里面写的源码,跟我本地看的不一样,它的简单,我的好复杂。

StackTc
StackTc 回复whb3299065: 好像是的 我mac装的1.8,但是 还是需要去理解。不能说难,就退
一年多之前 回复
whb3299065
whb3299065 可能是版本问题吧,我记得1.8的Map变化挺大
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
HashMap源码之get与put方法
HashMap是基于数组和链表来存储键值对对象的,我们简单看下get和put方法的源码。 1、我们调用put方法来存储键值对时,它先调用hash方法来计算hashcode,然后用hashcode和Entry数组的大小来做按位与操作,求出所在的Entry数组的下标位置。通过key与下标所在的Entry链表进行判断是否已经存在此Key,如果存在就重新设置value为新的值,不存在则加入到Entry链...
针对Java8的HashMap get与put方法分析
和JDK1.6的HashMap结构不同的是,JDK1.6中HashMap采用的是位桶+链表的方式,即我们常说的散列链表的方式,而JDK1.8中采用的是位桶+链表/红黑树的方式,也是非线程安全的。当某个位桶的链表的长度达到某个阀值的时候,这个链表就将转换成红黑树。 public class HashMap&lt;K,V&gt; extends AbstractMap&lt;K,V&gt; ...
HashMap源码-put方法
HashMap(1.8)HashMap的put方法: 代码如下: public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } 上面传入参数泛型K、V是在初始化HashMap对象时指定好的 核心方法putVal,传入参数:1.根据key计算得到的哈希值 2.key值 ...
HashMap中的数据结构与get,put源码解析
HashMap 执行流程:   首先构造方法: public HashMap() {         this.loadFactor = DEFAULT_LOAD_FACTOR; // all otherfields defaulted     } public HashMap(int initialCapacity) {         this(initialCapacit
HashMap的put方法源码的问题
[code=Java]rn public V put(K key, V value) rn K k = maskNull(key);rn int hash = hash(k); rn int i = indexFor(hash, table.length); //顺便问问这句,为什么是返回h & (length - 1)呢,这位运算结果的i对应着table里面的第一个元素?不懂rnrn for (Entry e = table[i]; e != null; e = e.next) rn if (e.hash == hash && eq(k, e.key)) rn V oldValue = e.value;rn e.value = value;rn e.recordAccess(this); //它的具体意思是当put调用的时候,这个方法就会被触发。这句的具体实现找不到?rn return oldValue;rn rn rnrn modCount++;rn addEntry(hash, k, value, i);rn return null;rn rn[/code]rn[code=Java]rn void addEntry(int hash, K key, V value, int bucketIndex) rn Entry e = table[bucketIndex];rn table[bucketIndex] = new Entry(hash, key, value, e); //e是next,怎么感觉table[bucketIndex]的next还是自己,而不是真正的下一个?这个是怎么回事rn if (size++ >= threshold)rn resize(2 * table.length);rn rn[/code]
HashMap源码解析——put方法
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }先看hash(key)函数。它是通过key的hashCode值计算hash码。//计算hash值的方法 通过键的hashCode来计算static final int hash(Object key) {
HashMap源码--(三)put方法
HashMap源码–(三)put方法Map内部的数据结构是以key-value的方式存数据。key和value都可以为空。 HashMap存取数据时是根据哈希算法计算数据存在位置,在相同哈希值计算的位置存放的数据结构是链表。添加元素使用方法put方法。 /** * 将指定的value和指定的key映射到map中。 * 如果map中包含这个key,则替换。 *
大话HashMap的put,get过程
put 最先判断桶的长度是否为0,为0的话则需要先对桶进行初始化操作,接着,求出hashcode并通过扰动函数确定要put到哪个桶中,若桶中没有元素直接插入,若有元素则判断key是否相等,如果相等的话,那么就将value改为我们put的value值,若不等的话,那么此时判断该点是否为树节点,如果是的话,调用putreeval方法,以树节点的方式插入,如果不是树节点,那么就遍历链表,如果找到了ke...
hashmap的数据结构以及put和get
一,hashmap数据结构。数据结构中有数组和链表来实现对数据的存储,但是这两种方式的优点和缺点都很明显: 1,数组存储,它的存储区间是连续的,比较占内存,故空间复杂度高。但是利用二分法进行查找的话,效率高,时间复杂度为O(1)。其特点就是:存储区间连续,查找速度快,但是占内存严重,插入和删除就慢。 2,链表查询,它的存储区间离散,占内存比较宽松,故空间复杂度低,但时间复杂度高,为O(n)。其特
HashMap中put()方法实现原理
突然想解剖HashMap实现原理,Map链表的作者源码如何实现?也可以丰富一下自己的编程思想,也想让读者看见如何观看别人源码的思路和方法。所以心血来潮的我,就来解析HashMap底层原理! 送给读者的话:一个合格的程序员一定要学会观看别人代码。这样子自己的开发也会很多思路和方法。希望国内软件开发越来越好。 首先看类 public class HashMap&amp;lt;K,V&amp;gt; ...
HashMap put()方法源码分析
JDK 1.6 public V put(K key, V value) { // 当前key为null的时候会调用putForNullKey()方法来保存值 if (key == null) return putForNullKey(value); // 根据key的hashCode()的方法计算出hash值(如果key对象的类没有重写hashCode(...
hashmap put方法问题。。。。
public V put(K key, V value) n if (key == null)n return putForNullKey(value);n int hash = hash(key);n int i = indexFor(hash, table.length);n for (Entry e = table; e != null; e = e.next) n Object k;n if (e.hash == hash && ((k = e.key) == key || key.equals(k))) n V oldValue = e.value;n e.value = value;n e.recordAccess(this);n return oldValue;n n nn modCount++;n addEntry(hash, key, value, i);n return null;n n void addEntry(int hash, K key, V value, int bucketIndex) n if ((size >= threshold) && (null != table)) n resize(2 * table.length);n hash = (null != key) ? hash(key) : 0;n bucketIndex = indexFor(hash, table.length);n nn createEntry(hash, key, value, bucketIndex);n n void createEntry(int hash, K key, V value, int bucketIndex) n Entry e = table;n table = new Entry<>(hash, key, value, e);n size++;n nn如果put 键索引相同key不同的元素,addEntry()怎么保存元素到链表尾部,createEntry()方法?
hashmap put方法问题
public V put(K key, V value) rn if (key == null)rn return putForNullKey(value);rn int hash = hash(key);rn int i = indexFor(hash, table.length);rn for (Entry e = table; e != null; e = e.next) rn Object k;rn if (e.hash == hash && ((k = e.key) == key || key.equals(k))) rn V oldValue = e.value;rn e.value = value;rn e.recordAccess(this);rn return oldValue;rn rn rnrn modCount++;rn addEntry(hash, key, value, i);rn return null;rn rn void addEntry(int hash, K key, V value, int bucketIndex) rn if ((size >= threshold) && (null != table)) rn resize(2 * table.length);rn hash = (null != key) ? hash(key) : 0;rn bucketIndex = indexFor(hash, table.length);rn rnrn createEntry(hash, key, value, bucketIndex);rn rn void createEntry(int hash, K key, V value, int bucketIndex) rn Entry e = table;rn table = new Entry<>(hash, key, value, e);rn size++;rn rnrn如果put 键索引相同key不同的元素,addEntry()怎么保存元素到链表尾部,createEntry()方法?
HashMap的put()方法小问题?
public void test(double sort[],Vector V)rn rn Map map=new IdentityHashMap();rn for(int k=0;k
Java8 HashMap put方法源码解析
Java8 put源码解析,大致可分为如下步骤:一:判断是不是第一次插入,如果是,则进行resize()二:如果通过hash&amp;amp;n-1计算出来的下标,里面如果没有元素,则在改下标下创建一个新的元素,然后put操作完成,然后判断是否扩容三:如果计算的下标下面已经存在元素,通过key值进行判断是否相同,如果相同,则结束,判断操作,在后去代码中,将新的值,覆盖为老的值,并返回老的值四:如果下标存在...
HashMap源码解析《一》put方法
在jdk1.8里边 hashmap的实现原理不仅仅只由位桶+链表实现 ,增加位桶+红黑树实现,在桶中链表存储的元素个数到达阈值时(默认为8),将在底层将链表转为红黑树,但因为我本人红黑树掌握的并不好,所以不讨论有关红黑树,本文主要讲解基础,hashmap的put方法,其他请等待下文;一,所涉及到的名词;1,bucket   桶,对于系统开始初始化hashmap的时候,会创建一个长度为capacit...
JDK8:HashMap源码解析:put方法
一、概述 Map的put方法接受两个参数,key和value,该方法用于存储键值对。 HashMap的put方法只有一行代码:   return putVal(hash(key), key, value, false, true); //参见:hash方法解析hash方法解析   可知put方法是一个方便用户使用的快捷方式,具体逻辑都是在putVal方法中实现的,我们就针对putVa...
HashMap源码注解 之 put()方法(六)
注意 , 本文基于JDK 1.8 HashMap#put() /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is r
HashMap的put方法源码解析_JDK1.7
建议大家把代码复制到开发工具中,我使用的是IntelliJ_IDEA,很好用、智能。 之后跟着put的主体方法,梳理各个小的方法,遇到加粗标注,便可转移方法。 /** * @Date:Create in 14:16 2018/2/5 * @Description:详解JDK1.7的HashMap.put方法 */ public class HashMap_put { //全局数...
HashMap的put方法源码解析_JDK8
package demo.JavaJdk8; import java.util.HashMap; import java.util.Map; /** * @author Xch */ public class MapDemo{ public void putDemo(){ Map&amp;lt;String,Integer&amp;gt; mapDemo=new HashMap...
HashMap的put方法源码的疑问,求指点
[code=java]rn final V putVal(int hash, K key, V value, boolean onlyIfAbsent,rn boolean evict) rn Node[] tab; Node p; int n, i;rn if ((tab = table) == null || (n = tab.length) == 0)rn n = (tab = resize()).length;rn if ((p = tab[i = (n - 1) & hash]) == null)rn tab[i] = newNode(hash, key, value, null);rn else rn Node e; K k;rn if (p.hash == hash &&rn ((k = p.key) == key || (key != null && key.equals(k))))rn e = p;rn else if (p instanceof TreeNode)rn e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);rn else rn for (int binCount = 0; ; ++binCount) rn if ((e = p.next) == null) rn p.next = newNode(hash, key, value, null);rn if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1strn treeifyBin(tab, hash);rn break;rn rn if (e.hash == hash &&rn ((k = e.key) == key || (key != null && key.equals(k))))rn break;rn p = e;rn rn rn if (e != null) // existing mapping for keyrn V oldValue = e.value;rn if (!onlyIfAbsent || oldValue == null)rn e.value = value;rn afterNodeAccess(e);rn return oldValue;rn rn rn ++modCount;rn if (++size > threshold)rn resize();rn afterNodeInsertion(evict);rn return null;rn rn[/code]rnhash是所添加键值对键的hash值rnrn看不懂第一个else中第一个if中的这句代码p.hash == hash,Node对象p既然已经指向了数组table这个索引上的元素,而且table该索引上的元素也不为null,说明数组table的这个索引位置上有一条存储了其他键值对信息的Node对象的链表,那p.hash是什么意思,整条链表的hash值?这样想怎么都觉得不对rnrn还有就是Nod对象 p的hash值什么什么时候算出来的,点进Node的源码发现只定义了hash这个变量,并没发现有给它赋值啊,那p.hash的结果又是怎么来的?rnrn想不通。。。。,求大神指点
[HashMap源码学习之路]---put方法中的hash方法介绍
HashMap中的put方法中的hash方法   以下是put方法的代码: public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }   当我第一次看到这个地方的时候,首先好奇的是这个hash 方法到底干了什么,于是我点了进去,看到下边这样的东西,顿时懵了: stat...
HashMap解析——HashMap的put方法返回值
首先,看一下源码:     public V put(K paramK, V paramV) { if (paramK == null) { return putForNullKey(paramV); } int i = hash(paramK.hashCode()); int j = indexFor(i, this.table.lengt...
HashMap底层详解-001-数据结构、put、get
今天小粉粉去某公司参加Java开发工程师的面试了。但是不太顺利,然后她遇见了小灰灰…… HashMap的数据结构 HashMap的数据结构是 数组+链表 的形式组成的。数组(这个table就是咱们看见的数组部分。) /** * The table, initialized on first use, and resized as * necessary. When a
HashMap原理及put与get方法调用过程
HashMap的原理 HashMap的数据结构为数组+链表,以key,value的形式存值,通过调用put与get方法来存值与取值。 它内部维护了一个Entry数组,得到key的hashCode值将其移位按位与运算,然后再通过跟数组的长度-1作逻辑与运算得到一个index值来确定数据存储在Entry数组当中的位置,通过链表来解决hash冲突问题。当发生碰撞了,对象将会储存在链表的下一个节点中。
java集合HashMap的put方法
首先我们需要对hashmap初始换容器大小 HashMap&amp;lt; String, String &amp;gt; hashMap = new HashMap&amp;lt;&amp;gt;(16); 如果我们的写的数字小于MAXIMUM_CAPACITY = 1 &amp;lt;&amp;lt; 30的值, 那么用我写的值,负责使用MAXIMUM_CAPACITY。值得注意的是我们在初始化大小的时候,容器的大小...
【java8】浅析HashMap之put()方法
从《浅析java8中HashMap的结构》这篇文章我们可以得知,hashMap的数据结构是数组+单链表。接下来咱们通过解读HashMap的put(K key, V value)方法来了解他的数据存储机制。 大致步骤如下图: 至于详细的步骤,请结合上图参考部分源码和注释: static final int hash(Object key) { int h; ...
Java HashMap的get(),put()算法时间复杂度
Java7和Java8的HashMap的put(),get()方法的时间复杂度是啥?还请从平均,最好,最坏的角度分析。谢谢
HashMap put()方法返回值解析
Map 存储k-v 对时的返回值: public static void main(String[] args) { Map&amp;lt;String,String&amp;gt; m= new HashMap&amp;lt;String,String&amp;gt;(); String s1= m.put(&quot;001&quot;,&quot;zhangsan&quot;); String s2=m.pu...
手写HashMap,实现put,get以及扩容
很晚了不多说了,直接贴代码,看完就会了解HashMap是如何实现数组+链表存储的,希望能给大家带来帮助,如果有疑问和纠正,请留言,第一时间回复 package coom.michelle.dream.myhashmap; import java.util.Objects; public class MyHashMap { public Node[
多线程下HashMap的put方法失效
在多线程环境下,使用HashMap进行put操作时存在丢失数据的情况,为了避免这种bug的隐患,强烈建议使用ConcurrentHashMap代替HashMap
HashMap中put方法底层源码理解
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {         Node&amp;lt;K, V&amp;gt;[] tab;         Node&amp;lt;K, V&amp;gt; p;         int n, i;         //判断tab是否已经创建,如果没有就初始化一个数组    ...
关于HashMap中put和putForCreate方法的区别
put方法源码:rnrn 1 public V put(K key, V value) rn 2 if (key == null)rn 3 return putForNullKey(value);rn 4 int hash = hash(key.hashCode());rn 5 int i = indexFor(hash, table.length);rn 6 for (Entry e = table[i]; e != null; e = e.next) rn 7 Object k;rn 8 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) rn 9 V oldValue = e.value;rn10 e.value = value;rn11 e.recordAccess(this);rn12 return oldValue;rn13 rn14 rn15 rn16 modCount++;rn17 addEntry(hash, key, value, i);rn18 return null;rn19 rnrnputForCreate方法源码:rnrn 1 private void putForCreate(K key, V value) rn 2 int hash = (key == null) ? 0 : hash(key.hashCode());rn 3 int i = indexFor(hash, table.length);rn 4 for (Entry e = table[i]; e != null; e = e.next) rn 5 Object k;rn 6 if (e.hash == hash &&rn 7 ((k = e.key) == key || (key != null && key.equals(k)))) rn 8 e.value = value;rn 9 return;rn10 rn11 rn12 createEntry(hash, key, value, i);rn13 rnrn 感觉这两个方法实现的功能是一样的啊,都是插入对象。为什么要写两个不同的方法啊 。 还有下边这个putAllForCreate方法,为什么调用的是putForCreate方法而不是put方法rnrn1 private void putAllForCreate(Map m) rn2 for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) rn3 Map.Entry e = i.next();rn4 putForCreate(e.getKey(), e.getValue());rn5 rn6
HashMap中put方法底层实现(JDK8)
1.进入put方法的实现 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } 2.跳转到putVal方法 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, b...
【JavaSE】Map集合,HashMap的常用方法put、get的源码解析
Map集合 Collection集合的特点是每次进行单个对象的保存,如果现在要进行一对对象(偶对象)的保存就只能使用Map集合来 完成,即Map集合中会一次性保存两个对象,且这两个对象的关系:key=value结构。这种结构最大的特点是可以通 过key找到对应的value内容。 首先来观察Map接口定义: public interface Map&amp;lt;K,V&amp;gt; 在Map接口中有如下常用方...
Java数据结构详解(十二)- HashMap
HashMap基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的
HashMap:内部组成&put:、get、remove方法大致逻辑&总结
源码基于java1.8 一、传统 HashMap的缺点 (1)JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。 (2)当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。 (3)针...
【Java】HashMap源码分析—put、get、resize方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法: put() get() resize() 首先介绍resize()这个方法,在我看来这是HashMap中一个非常重要的方法,是用来调整HashMap中table的容量的,在很多操作中多需要重新计算容量。 源码如下: final Node&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;K,V&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp
HashMap的get()方法的工作原理
HashMap的get()方法的工作原理 首先根据对象的Hash值进行数组方面的寻找,然后找到这个数组之后,判断key是不是唯一,如果key唯一,则直接返回,如果不唯一,则使用equals进行值的判断,最后返回数据。 ...
HashMap源码注解 之 get()方法(五)
注意 , 本文基于JDK 1.8 HashMap#get() /** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formall
相关热词 c#入门推荐书 c# 解码海康数据流 c# xml的遍历循环 c# 取 查看源码没有的 c#解决高并发 委托 c#日期转化为字符串 c# 显示问号 c# 字典对象池 c#5.0 安装程序 c# 分页算法