一、前情回顾:在程序中有时候需要存放对象,容器应运而生。容器分为集合和Map。集合在这里不说,说说Map。Map在英语中是地图的意思,这个名字真是起的好,可以让人顾名思义。Map,就是存放键值对的结构。也就是说,只要找到键,就能找到对应的值,就跟查字典一样。

二、Map工作效率的深层原理:

1.上面说到查询map就是查询键,只要键找得到,值就会对应的找得到。所以怎么找到键,就是访问Map的效率的瓶颈所在。

2.那么如何找到键呢?其中一个好办法就是把键排序,然后按照二分法查找。二分法就不用介绍了吧?

3.散列(HashMap)则更进一步。他把键相关的信息保存在一个数组中。因为数组时访问速度最快的数据结构。这样可以大大提高效率。但是数组中存储的是键的相关信息,而不是键本身。因为Map的大小是不确定的,而数组的大小是确定的,所以问题来了,怎么把不确定size的Map的键的相关信息存储在数组中呢?

4.那就是数组并不保存键本身,只保存于键相关的信息,这个相关信息就是每一个键对象生成的数字,将其作为数组的下表,这个数字就是散列码,即hashCode()方法。

5.不同的键可以产生相同的散列码,对应于数组的相同下标。这样就解决了数组大小不变的问题。即:数组中的每一个具体的位置,可以根据Map的大小存储一个或多个Map基本元素,这样就会保证Map可以自由调节大小。Map小了,把数组填不满,Map大了,就往数组的同一个位置多填几个值。其数据结构如下图:

代码如下

package test;

import java.util.Map;

/**
* @author 笑傲独行侠
* @description:
* @Date: 2019/7/9 13:55
*/
public class MapEntry<K, V> implements Map.Entry<K, V> {
private K key;
private V value; public MapEntry(K key, V value) {
this.key = key;
this.value = value;
} @Override
public K getKey() {
return key;
} @Override
public V getValue() {
return value;
} @Override
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
}
package test;

import java.util.*;

/**
* @author 笑傲独行侠
* @description: 理解HashMap的深层原理
* @Date: 2019/7/9 11:33
*/
public class SimpleHashMap<K, V> extends AbstractMap<K, V> {
static final int SIZE = 997;//定义数组的大小,尽量大一下,使得一个map尽量存入不同的下标数组中
LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];//定义一个数组,存放键的相关信息,数组中是List public V put(K key, V value) {
V oldValue = null;
//先计算key的hashCode值,再处理一下算出对应的数组下标
int index = Math.abs(key.hashCode()) % SIZE; //如果该下标对应的还没有值,就先new一个List
if (buckets[index] == null) {
buckets[index] = new LinkedList<MapEntry<K, V>>();
} //如果该下标已经有一个key存放在其中,就将当前key添加到该List中。
LinkedList<MapEntry<K, V>> bucket = buckets[index];
MapEntry<K, V> pair = new MapEntry<K, V>(key, value);
boolean found = false;
ListIterator<MapEntry<K, V>> it = bucket.listIterator();
while (it.hasNext()) {
MapEntry<K, V> iPair = it.next();
if (iPair.getKey().equals(key)) {
oldValue = iPair.getValue();
it.set(pair);
found = true;
break;
}
}
//定义一个Boolean变量,如果要存入的键已经存在,则替换该键对应的值,如果不存在则添加
if (!found)
buckets[index].add(pair);
return oldValue;
} @Override
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if (buckets[index] == null)
return null;
for (MapEntry<K, V> iPair : buckets[index]) {
if (iPair.getKey().equals(key))
return iPair.getValue();
}
return null;
} @Override
public Set<Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> set = new HashSet<>();
for (LinkedList<MapEntry<K, V>> bucket : buckets) {
if (bucket == null) {
continue;
}
for (MapEntry<K, V> mPair : bucket) {
set.add(mPair);
}
}
return set;
} public static void main(String[] args) {
SimpleHashMap<String, String> m = new SimpleHashMap<>();
m.put("111", "huhhu");
m.put("111", "huhhu");
m.put("111", "huhhu");
m.put("111", "huhhu");
System.out.println(m);
System.out.println(m.get("ERITREA"));
System.out.println(m.entrySet());
}
}

HashMap为什么效率高?来看看这个小demo的更多相关文章

  1. 遍历hashMap对效率的影响

    测试环境:jdk1.7.0_79\Processor 1.7 GHz Intel Core i5 遍历Map的方式有很多,通常场景下我们需要的是遍历Map中的Key和Value. 写了两个方法: pu ...

  2. 为什么switch...case语句比if...else执行效率高

    在C语言中,教科书告诉我们switch...case...语句比if...else if...else执行效率要高,但这到底是为什么呢?本文尝试从汇编的角度予以分析并揭晓其中的奥秘. 第一步,写一个d ...

  3. 【OCP、OCM、高可用等】小麦苗课堂网络班招生简章(从入门到专家)--课程大纲

    [OCP.OCM.高可用等]小麦苗课堂网络班招生简章(从入门到专家)--课程大纲 小麦苗信息 我的个人信息 网名:小麦苗 QQ:646634621 QQ群:618766405 我的博客:http:// ...

  4. C# 多线程 Parallel.For 和 For 谁的效率高?那么 Parallel.ForEach 和 ForEach 呢?

    还是那句话:十年河东,十年河西,莫欺少年穷. 今天和大家探讨一个问题:Parallel.For 和 For 谁的效率高呢? 从CPU使用方面而言,Parallel.For 属于多线程范畴,可以开辟多个 ...

  5. PHP 比 Java 的开发效率高在哪?

    PHP 比 Java 的开发效率高在哪? 现在很多互联网应用都是php开发的,在很多人的观念里已经把php与java分到了两个开发领域,php是互联网,java是企业应用. 都说php的开发效率高,更 ...

  6. 为什么golang的开发效率高(编译型的强类型语言、工程角度高、在开发上的高效率主要来自于后发优势,编译快、避免趁编译时间找产品妹妹搭讪,既是强类型语言又有gc,只要通过编译,非业务毛病就很少了)

    作者:阿猫链接:https://www.zhihu.com/question/21098952/answer/21813840来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出 ...

  7. 笨重的mfc还在基于系统控件,熟练的mfc工程师还比不过学习Qt一个月的学生开发效率高(比较精彩,韦易笑)

    作者:韦易笑链接:https://www.zhihu.com/question/29636221/answer/45102191来源:知乎著作权归作者所有,转载请联系作者获得授权. 更新:擦,本来只有 ...

  8. 你还在认为 count(1) 比 count(*) 效率高?

    你还在认为 count(1) 比 count(*) 效率高? 3 很多人认为count(1)执行的效率会比count()高,原因是count()会存在全表扫描,而count(1)可以针对一个字段进行查 ...

  9. 为什么说在使用多条件判断时switch case语句比if语句效率高?

    在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...

随机推荐

  1. 20201207-2 openpyxl 库与模块导入

    1-1 import openpyxl # 通过文件路径,打开工作簿 wb1 = openpyxl.load_workbook('./demo_excel.xlsx') # 用 Workbook() ...

  2. Service Cloud 零基础(二)Knowledge浅谈

    本篇参考:https://trailhead.salesforce.com/content/learn/projects/set-up-salesforce-knowledge https://tra ...

  3. Hadoop核心-HDFS

    上一篇我们熟悉了hadoop,本篇讲解一下hadoop第一个核心HDFS. 一.概述 HDFS是一个分布式文件存储系统,以流式数据访问模式存储超大文件,将数据分块存储到一个商业硬件集群内的不同机器上, ...

  4. writeup | 你知道php的备份文件吗

    题目地址:https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5064 转载请注明出处作者 ...

  5. sqli-labs 18-19 --Header_injection

    sqli-labs 18 知识点 头部注入 报错注入 使用的函数: updatexml (XML_document, XPath_string, new_value); 第一个参数:XML_docum ...

  6. 跟我一起学Redis之高可用从主从复制开始

    前言 现在遇到高并发场景时,缓存技术应该算是性能优化的第一步,缓解数据库压力的同时还能提高访问效率,而Redis应该是绝大多数应用场景的首选.但是尽快Redis性能再优秀,在当今高并发场景下,一台服务 ...

  7. 【进阶之路】线程池拓展与CompletionService操作异步任务

    大家好,我是练习java两年半时间的南橘,小伙伴可以一起互相交流经验哦. 一.扩展ThreadPoolExecutor 1.扩展方法介绍 ThreadPoolExecutor是可以扩展的,它内部提供了 ...

  8. 程序猿的浪漫:用python画动态爱心

    初级画心 学Python,感觉你们的都好复杂,那我来个简单的,我是直接把心形看作是一个正方形+两个半圆:

  9. HTC Vive使用WebVR的方法以及启用后头显无画面的解决方法

    1.下载支持WebVR的浏览器. 笔者使用的是HTC Vive,故下载了Firefox的Nightly版本[下载地址]. 2.Nightly 开启WebVR的步骤[引用自Mozilla VR] 1.从 ...

  10. MGRE综合实验

    实验要求: 实验拓扑: 一. R1-2-3构建星型结构的MGRE结构,R1为中心站点,假设R1的共有IP为固定地址 1. 配置IP地址 2. 配置缺省 3. 配置MGRE环境 在中心站点上: 在分支站 ...