当前位置: 首页 > news >正文

你所忽略的HashMap

为什么突然之间要说HashMap呢,是因为最近一个学长问了我许多问题,才发现我在学知识的时候思考的真的是太少 了,因此我想要改变这种方式,接下来让我们说说HashMap吧
1、首先呢,先了解下HashMap
 继承包以及实现的接口
关于HashMap的方法
这里写图片描述

这里写图片描述

对于HashMap有了基本的了解,那么我们来谈谈HashMap中的key和value,相信很多人都知道也使用过当value为null,那么key是否又为空呢?
答案是key和value都可为空,各自的用法又有什么作用?等等之类的问题
关于HashMap中的使用,我觉得有篇博客写的不错HashMap的详解
1、key 和value为什么可以为空?key为空是放在哪里?

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        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;
            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;
    }
   */
    private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }
  private void putForCreate(K key, V value) {
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);

        /**
         * Look for preexisting entry for key.  This will never happen for
         * clone or deserialize.  It will only happen for construction if the
         * input Map is a sorted map whose ordering is inconsistent w/ equals.
         */
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                e.value = value;
                return;
            }
        }

        createEntry(hash, key, value, i);
    }

以上是HashMap中源码的一部分,这也是为什么key和value为什么为空,(PS:如果在问我一次,我觉得我会傻逼的回答,在HashMap源码中定义了为空时的用法,这也是为什么为空,有点傻,不要介意)。
key为空时是放在数组下标为空的地方

2、当key不为空时,怎么样存储?
当我们在HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(及下标),如果数组位置上已经存放有其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将元素放在次数组中的该位置上。

    final Entry<K,V> removeEntryForKey(Object key) {
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);
        Entry<K,V> prev = table[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                modCount++;
                size--;
                if (prev == e)
                    table[i] = next;
                else
                    prev.next = next;
                e.recordRemoval(this);
                return e;
            }
            prev = e;
            e = next;
        }

        return e;
    }

3、key的默认值是多少?为什么是这么多?
这个问题,个人觉得看源码吧

//key的默认大小是16
  static final int DEFAULT_INITIAL_CAPACITY = 16;
//为什么是16
/*按照位运算,刚好是求余操作,也就是2的整数次幂方*/
   static int indexFor(int h, int length) {
        return h & (length-1);
    }

4、HashMap什么时候扩容?
HashMap中有个加载因子,当加载因子超过0.75时就会扩容。
原话是这样的:
HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,通过调用 rehash 方法将容量翻倍。

通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地降低 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

以上是我的一些理解,如果有更好的理解,欢迎评论!

相关文章:

  • 随想
  • Java中的Base64(源码)
  • Java中Base64(实例)
  • Java数据类型及运算符
  • SQL server基本使用示例一
  • SQL Server基本使用示例三
  • Oracle12c的安装
  • 编程一
  • Java链接数据库
  • 编程二
  • 设计一个一百亿的计算器
  • Java技术体系和学习纲要
  • Eclipse调优和设置
  • Java语法基础
  • ECMAScript入门(七)--Module语法
  • spring security oauth2 password授权模式
  • SpriteKit 技巧之添加背景图片
  • Vue 2.3、2.4 知识点小结
  • 翻译--Thinking in React
  • 观察者模式实现非直接耦合
  • 来,膜拜下android roadmap,强大的执行力
  • 悄悄地说一个bug
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 数据可视化之 Sankey 桑基图的实现
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 通过几道题目学习二叉搜索树
  • Java性能优化之JVM GC(垃圾回收机制)
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ​用户画像从0到100的构建思路
  • #单片机(TB6600驱动42步进电机)
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (02)Hive SQL编译成MapReduce任务的过程
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (算法)求1到1亿间的质数或素数
  • (转) Android中ViewStub组件使用
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)编辑寄语:因为爱心,所以美丽
  • **python多态
  • .aanva
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .Net6使用WebSocket与前端进行通信
  • .NET大文件上传知识整理
  • .NET中使用Protobuffer 实现序列化和反序列化
  • [1159]adb判断手机屏幕状态并点亮屏幕
  • [1181]linux两台服务器之间传输文件和文件夹
  • [20150321]索引空块的问题.txt
  • [AX]AX2012开发新特性-禁止表或者表字段
  • [BJDCTF2020]The mystery of ip1
  • [bug总结]: Feign调用GET请求找不到请求体实体类
  • [CDOJ 838]母仪天下 【线段树手速练习 15分钟内敲完算合格】
  • [CLR via C#]11. 事件