热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HashMap理解(1)-知识积累

一点一点学源码分析下面代码做了什么Map<String,Integer>mapnewHashMap<String,Integer>();map.put

一点一点学源码

分析下面代码做了什么

Map map = new HashMap();
map.put("张三",10);
map.put("李四",20); Integer age
=map.get("张三");

1.初始化

接口  Map,Cloneable, Serializable 
                    |
            抽象类 AbstractMap
                    |
            具体实现类 HashMap                                                  
Map map = new HashMap();调用无参构造,给全局final变量loadFactor赋初值 0.7
final float loadFactor;
static final float DEFAULT_LOAD_FACTOR = 0.75f;

public HashMap() {
      this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

2,map.put("张三",10);

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
}
//传入参数为 (774882,"张三",10,false,true)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {

    /**
    *  Node{  
    *     final int hash;
    *     final K key;
    *     V value;
    *     Node next;
    *  }
    */
    Node[] tab; 
    Node p; 
    int n,i;

    /**
    *以上是该方法四个局部变量
    *重点关注该方法对该实体类全局变量的修改
    *该类中涉及到全局信息的有
    *    static final int TREEIFY_THRESHOLD = 8;
    *    transient Node[] table;
    *    transient int modCount;
    *    transient int size;
    *    int threshold;
    */

    //全局变量table初始化时赋值null
    if ((tab = table) == null || (n = tab.length) == 0)  
        //调用resize方法 n为16即tab数组初始化长度16 该方法执行时执行了    table = (Node[])new Node[16];
        n = (tab = resize()).length;  
        //p=tab[2]==null 
    if ((p = tab[i = (n - 1) & hash]) == null)
        //tab[2]=Node{hash:774882,key:"张三",value:10,next:null} 即table[2]=Node{hash:774882,key:"张三",value:10,next:null}
        tab[i] = newNode(hash, key, value, null);
    # else {//数组空间未被占用
    #     Node 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)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;//该值为1
    if (++size > threshold)//size=1  threshold该值在resize方法中  threshold=16*0.75=12
        resize();
    afterNodeInsertion(evict); // Callbacks to allow LinkedHashMap post-actions 本类无方法体
    return null;//张三 10被存储到table数组的第2位置中
}

2,map.put("李四",20);

//传入参数为 (842049,"李四",20,false,true)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {

    /**
    *  Node{  
    *     final int hash;
    *     final K key;
    *     V value;
    *     Node next;
    *  }
    */
    Node[] tab; 
    Node p; 
    int n,i;

    /**
    *以上是该方法四个局部变量
    *重点关注该方法对该实体类全局变量的修改
    *该类中涉及到全局信息的有
    *    static final int TREEIFY_THRESHOLD = 8;
    *    transient Node[] table;
    *    transient int modCount;
    *    transient int size;
    *    int threshold;
    */

    //此时tab={;;;table[2]=Node{hash:774882,key:"张三",value:10,next:null};;;} n=16
    if ((tab = table) == null || (n = tab.length) == 0)  
        //不为null跳过初始化
        n = (tab = resize()).length;   
    if ((p = tab[i = (n - 1) & hash]) == null) //tab[1]=null
        //tab[1]=Node{hash:842049,key:"李四",value:20,next:null} 即table[1]=Node{hash:842049,key:"李四",value:20,next:null}
        tab[i] = newNode(hash, key, value, null);
    # else {//数组空间未被占用 下次查看该分支 先研究一下链表和树
    #     Node 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)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;//该值为2
    if (++size > threshold)//size=2  threshold=16*0.75=12//下次查看该分支 超过阈值扩容
        resize();
    afterNodeInsertion(evict); // Callbacks to allow LinkedHashMap post-actions 本类无方法体
    return null;//李四 20被存储到table数组的第1位置中
}

4,map.get("张三")

public V get(Object key) {
        Node e;
//获取该位置的Node节点,直接获取该value值 返回10
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
//参数(774882,"张三")
final Node getNode(int hash, Object key) {
        Node[] tab;
        Node first, e; 
        int n; 
        K k;
        /**
        *table[1]=Node{hash:842049,key:"李四",value:20,next:null}
        *table[2]=Node{hash:774882,key:"张三",value:10,next:null}
        */
        if ((tab = table) != null && (n = tab.length) > 0 &&
                (first = tab[(n - 1) & hash]) != null) {   //first=table[1]=Node{;;;"张三"}
            if (first.hash == hash && 
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;//first.next==null 直接返回该Node 该位置无链表或树
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode)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;
    }

 简单理解即数据被存储到HashMap的

transient Node[ ] table;  中了Node继承了Entry维护key,value键值对,查询时先获取Node然后获取value

未考虑Node中key相同 value不同的情况以及 table数组大小超过阈值扩容情况,下次查看 


推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文详细介绍了 com.apollographql.apollo.api.internal.Optional 类中的 orNull() 方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 传统上,Java 的 String 类一直使用 char 数组来存储字符数据。然而,在 Java 9 及更高版本中,String 类的内部实现改为使用 byte 数组。本文将探讨这一变化的原因及其带来的好处。 ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • C语言编写线程池的简单实现方法
    2019独角兽企业重金招聘Python工程师标准好文章,一起分享——有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带 ... [详细]
  • Spring Data JdbcTemplate 入门指南
    本文将介绍如何使用 Spring JdbcTemplate 进行数据库操作,包括查询和插入数据。我们将通过一个学生表的示例来演示具体步骤。 ... [详细]
  • 本文总结了Java初学者需要掌握的六大核心知识点,帮助你更好地理解和应用Java编程。无论你是刚刚入门还是希望巩固基础,这些知识点都是必不可少的。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • Spring Boot 中配置全局文件上传路径并实现文件上传功能
    本文介绍如何在 Spring Boot 项目中配置全局文件上传路径,并通过读取配置项实现文件上传功能。通过这种方式,可以更好地管理和维护文件路径。 ... [详细]
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 重要知识点有:函数参数默许值、盈余参数、扩大运算符、new.target属性、块级函数、箭头函数以及尾挪用优化《深切明白ES6》笔记目次函数的默许参数在ES5中,我们给函数传参数, ... [详细]
  • 深入解析 Lifecycle 的实现原理
    本文将详细介绍 Android Jetpack 中 Lifecycle 组件的实现原理,帮助开发者更好地理解和使用 Lifecycle,避免常见的内存泄漏问题。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
author-avatar
海边的迷思萝_160
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有