重复造轮子(1) --- 手写HashMap

一篇搞懂HashMap,手写HashMap 手撕HashMap 阅读详情

手写Hashmap代码:

首先我们需要了解jdk里面hashmap的源码部分,如果对于hashmap的源码有了解的朋友,就应该会知道hashmap里面的这段代码:

 

是的,这是一段经典的node节点代码,我们可以吧hashmap看成一个存储单向链表的数组,然后每个链表里面的元素都是包含有相应的k v值。

参考源码的内容,我写了一小段自己关于hashmap的设计代码:

首先是一个父类接口的设计:

/**
 * 作者:idea
 * 日期:2018/6/25
 * 描述:
 */
public interface MyMap<K,V> {
    public V get(K key);
    public V put(K key,V value);
    interface IEntry<K,V>{
        public K getKey();
        public V getValue();
    }

}

设计好了父类接口之后,编写一个MyHashMap类实现这个接口即可了。

在MyHashMap类里面需要编写相应的初始化参数:


/**
 * 作者:idea
 * 日期:2018/6/25
 * 描述:
 */
public class MyHashMap<K,V> implements MyMap<K,V> {

    private static final int DEAFULT_SIZE=1<<4;  //16
    private static final float DEFAULT_LOAD_SIZE=0.76f; //负载因子
    private int deaultInitSize;  //默认大小
    private float deaultLoadSize; //默认负载因子
    private int entrySize; //默认的entry数组数量

    private Entry<K,V>[] table=null;

    public MyHashMap(){
        this(DEAFULT_SIZE,DEFAULT_LOAD_SIZE);
    }

    //采用了门面模式
    //仔细观察下,你会发现,其实这里使用到了“门面模式”。这里的2个构造方法其实指向的是同一个,但是对外却暴露了2个“门面”!
    public MyHashMap(int deaultInitSize,float deaultLoadSize){
        this.deaultInitSize=deaultInitSize;
        this.deaultLoadSize=deaultLoadSize;
        table=new Entry[this.deaultInitSize];
    }

接下来便是核心的get和put方法了:

get方法的实现如下所示:

    @Override
    public V get(K key) {
        int index=hash(key)&(deaultInitSize-1);
        if(table[index]==null){
            return null;
        }else{
            Entry<K,V> e=table[index];
            do{
                if(e.getKey().equals(key)){
                    return e.getValue();
                }
                e=e.next;
            }while(e!=null);
        }
        return null;
    }

关于put部分方法的实现如下所示:从函数的实现可以看出resize是一个比较消耗性能的部分。

 @Override
    public V put(K key, V value) {
        if(entrySize>=deaultInitSize*deaultLoadSize){
            //扩容操作
            resize(deaultInitSize*2);
        }
        int index=hash(key)&(deaultInitSize-1);
        if(table[index]==null){
            table[index]=new Entry<K,V>(key,value,null);
            entrySize++;
        }else{
            Entry<K,V> tempEntry=table[index];
            Entry<K,V> e=tempEntry;
            while(e!=null){
                if(key ==e.getKey()||e.getKey().equals(key)){
                    e.setValue(value);
                    break;
                }
                e=e.next;
            }
            //这里面需要联想一下链表那边的引用,next指示了原有的链表地址,所以第三个参数是tempentry
            table[index]=new Entry<K,V>(key,value,tempEntry);
            entrySize++;
        }
        return value;
    }

在上述的截图里面,读者会看到一个叫做hash的函数,这是我自己封装的一个关于hash值计算的函数,可以通过输入的key自动算出相应的hash值。以及一个rehash函数和resize函数都是用于提供扩容数组的功能。

关于hash函数里面的>>>和^操作符,可能大多数人在平时编程里面接触的不多,在这里我简单提及一下:

<<          左移运算符,num << 1,相当于num乘以2

>>          右移运算符,num >> 1,相当于num除以2

>>>         无符号右移,忽略符号位,空位都以0补齐

 如:

a=00110111,则a>>2=00001101,a>>>2=00001101,

b=11010011,则b>>2=11110100,b>>>2=00110100

 

    //自定义的hash算法
    private int hash(Object key){
        int hashcode= Objects.hashCode(key);
        hashcode^=(hashcode>>>20)^(hashcode>>>12);
        return hashcode^(hashcode>>>7)^(hashcode>>>4);
    }

    //重新扩容,核心在rehash里面
    private void resize(int i){
        Entry[] newTable=new Entry[i];
        this.deaultInitSize=i;
        this.entrySize=0;
        System.out.println("newTable size:--------->"+newTable.length);
        rehash(newTable);

    }

    //扩容算法的核心部分
    private void rehash(Entry<K,V>[] newTable){
        List<Entry<K,V>> entryList=new ArrayList<Entry<K,V>>();
        for(Entry<K,V> e:table){
            while(e!=null) {
                entryList.add(e);
                e=e.next;
            }
        }
        if(newTable.length>0){
            table=newTable;
        }
        for (Entry<K,V>  entry : entryList) {
            put(entry.getKey(),entry.getValue());
        }
    }

如果读者有兴趣的话,可以去看看jdk源码里面关于hashcode的生成函数:

 

在Objects类里面,点开源码追溯hashCode函数,你会看到以下内容:(jdk1.8环境里面)

 

这个时候会看到一个叫做native的声明修饰符。

关于native这个关键字而言,说明修饰的方法是一个原生态的函数,方法的对应实现并不是在当前文件中,而是在别的C/C++文件里面。

由于在java语言里面,不允许直接对操作系统的底层进行直接的访问和操作,于是在jdk里面提供了一个JNI接口用于供java代码调用其他语言编写的代码内容。

最后便是相应的测试代码了:

/**
 * 作者:idea
 * 日期:2018/6/25
 * 描述:
 */
public class Test {


    public static void main(String[] args) {
        MyHashMap mh=new MyHashMap();
        for(int i=0;i<10000;i++){
            mh.put(i,i);
        }
        for(int i=0;i<10000;i++) {
            if (mh.get(i) != null) {
                System.out.println(mh.get(i));
            }
        }

    }
}

测试成功之后,相应的输出如下所示:

 

当然,自己写的hashmap和jdk里面的源码差距还是有些大的,但是自己亲自手写过一遍集合框架的内容之后,确实能提升自己一些能力。

【学习记录】IIC驱动ICM42670+卡尔曼滤波+四元数姿态角解算 ICM42670陀螺仪可以使用iic驱动,单片机平台使用GD32f305VE。 阅读详情

相关推荐

Fluent VOF造波从入门到放弃?手把手教你用k-w SST模型搞定波浪模拟

本文详细介绍了使用Fluent VOF和k-w SST模型进行波浪模拟的实战技巧,从参数设置到结果优化,帮助用户避开常见误区。通过工业项目验证的配置方案,提升波浪模拟的准确性和计算效率,特别适合处理多相流和复杂湍流场景。

weixin_27102543的博客 422

手写简易版HashMap

前言 我们发现HashMap在jdk 1.8之后用了数组+链表+红黑树的结构,为了加深对HashMap底层设计的理解,自己也读了一些hashmap相关的源码,因此想通过手写hashmap去理其底层的操作原理。 HashMap源码解析 目标: 基于数组+链表结构实现一个HashMap,包含get()、put()、remove()方法。 环境: jdk1.8 知识储备: hashcode, 幂等性, 数组,链表,红黑树。 原理: Hash...

Dream_it_possible!的博客 2883

基于Web的智能家居(源码+开题)

实践上,智能家居系统的普及和应用将极大改善人们的居住体验,提高生活质量,同时也有助于促进智能家居产业链的发展和完善,为社会经济发展注入新的活力。此外,本研究还将对基于Web的智能家居系统的用户体验进行深入研究,通过用户调研和数据分析,不断优化系统功能和界面设计,提升用户的使用体验和满意度。针对以上问题,本研究将综合运用物联网、云计算、大数据等新一代信息技术,通过系统架构设计、功能模块开发、安全性保障、用户体验优化等多个方面的研究工作,力求为基于Web的智能家居系统的研发和应用提供全面而有效的解决方案。

sryue06的博客 1902

[Java] 手写一个简单的HashMap

手写一个简单的HashMap

YANG_sena的博客 1141

MT 103 Single Customer Credit Transfer单笔客户转账

MT 103 Single Customer Credit Transfer单笔客户转账 MT103电文能通过三种方式交换,依赖电文使用的业务场景。 (1)   核心MT103电文是一个通用电文,发送和接收此电文不需要在电文用户组(MUG)注册。允许使用所有MT103电文域来交换单客户转账,除了77T域(信封内容)。MT103电文如果是根据预先约定的双边/多边规则的格式,则可以直通处理。 (

shuytu 1万+

<IBM AIX> 《HACMP 实用手册和命令 HA切换手册》 - 鸿篇巨制,全网最全

操作命令检查磁盘预留策略要将磁盘预留策略更改为 no_reserve集群状态实用程序查看集群状态是否正常SMIT System Management (C-SPOC)Cluster ServicesShow Cluster Services 面板上的选项或 lssrc 命令查看资源组、资源组对应的VG、资源组对应的APPLICATION SERVER# ./cldispsmit常用命令F3退出F4列表Esc+6或者F6查看命令Esc+7或者F7选择多项检查状态。

Else 的博客 3361

手写HashMap

基于hash算法、数组、单向链表,参考jdk中的HashMap集合,手写实现HashMap集合;基于ArrayList实现HashMap集合

weixin_47844533的博客 583

Ardupilot chibios主函数学习(1)

目录 文章目录目录摘要第一部分chibios主函数**(1)主回调函数入口****(2)主回调函数入口****(3)主回调函数入口****(4)主回调函数入口**1.函数hal.scheduler-&amp;amp;amp;amp;amp;amp;amp;gt;init()分析 摘要 本节主要记录自己学习Ardupilot的 chibios代码过程,欢迎批评指正。 第一部分chibios主函数 (1)主回调函数入口 AP_HAL_MAIN_...

陌城烟雨 4243

HashMap源码手写简易篇(数组+链表)

java

qq_43649937的博客 805

STM32驱动HC-SR04超声波模块

本篇文章将带大家使用HAL库驱动HC-SR04超声波模块。超声波模块作为智能小车必备的模块,要学习智能小车的同学是必须掌握好这个模块的使用的。HC-SR04是一种常用的超声波传感器模块,也被称为超声波测距模块,广泛应用于各种自动化控制和测距系统中。它通常由超声波发射器、接收器、控制电路和外壳组成,可以实现非接触式的距离测量。下面是HC-SR04超声波模块的一些特性和技术参数:距离测量范围:2cm ~ 400cm(可调)。测量精度:0.3cm。工作电压:DC 5V。工作电流:15mA。

m0_49476241的博客 7682

Unity之OpenXR+XR Interaction Toolkit接入HTC Vive

目前VR领域,最流行的设备要当属HTC VIVE了。以前在Unity端接入HTC VIVE设备时,都是通过SteamVR+VRTK来接入的。但是随着Unity的版本升级和OpenXR标准的流行,再加上VR设备的逐渐增多。SteamVR+VRTK的方式已经无法更好的满足大家的需求。

TxNet 4136

程序员,你还没造过轮子吗?

在我们程序员的圈子,有一句话非常流行,就是:不要重复造轮子。原文是:Stop Trying to Reinvent the Wheel,意思是:不要重复发明轮子。但是这是两个概念:造轮子和发明轮子。 因为前人在发明出圆形的轮子之前,已经尝试过其它形状的轮子了,发现都不成功,最后发现圆形的轮子是成功的,才选择了圆形。这是在发明轮子。那后人肯定就不要再去发明轮子了,因为圆形已经被证明是可用的了。 那什么是造轮子呢?就是指改进轮子,于是就有了石轮、木轮、空心木轮和气轮等。这就叫造轮子。 从...

Charles的博客 868

最新Python爬虫实战(入门爬虫篇)——案例13:某乎热榜数据采集(详细爬虫思路截图+抓包动图演示+完整爬虫代码+详细注释)

本次案例通过Python爬虫技术,成功实现了基于Cookies认证的某乎热榜数据爬取与Excel保存。代码采用模块化设计,包含Cookies解析、HTML请求、结构化解析、Excel持久化等完整流程;通过配置浏览器请求头+Cookies认证,有效突破某乎基础反爬策略,保证请求稳定性。整个爬虫逻辑遵循“Cookies认证 → 页面请求 → HTML解析 → 数据清洗 → 保存到Excel”的标准流程,与需要会话验证的网站爬取范式高度一致。Cookies解析与认证。

努力让自己发光,对的人才能迎着光而来 33万+

程序员为什么热衷于造轮子:从 CodeGuide 仓库源码实践看造轮子与成长晋升的关系

> 导读:本文以 CodeGuide 开源仓库中作者小傅哥的工程实践为主线,回答一个困扰很多程序员的问题——"造轮子到底值不值得"。文章完整梳理了仓库内可考证的多个自研轮子(RPC 通信组件、用 Java 实现 JVM、分布式任务中间件 DcsSchedule、服务治理白名单中间件、Netty 仿桌面版微信 IM 等)从需求到实现的源码细节,并深入讨论造轮子与升职加薪的真实关系、如何面对"不要重复

gitblog_00500的博客 585

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Java常用17个工具类方法,提升开发效率的“轮子”,避免重复造轮子

首先出场的是java.util包下的Collections类,该类主要用于操作集合或者返回集合,我个人非常喜欢用它。在工作中经常有对集合排序的需求。看看使用Collections工具是如何实现升序和降序的: 执行结果: 1.2 获取最大或最小值 有时候需要找出集合中的最大值或者最小值,这时可以使用Collections的max和min方法。例如: 执行结果: 1.3 转换线程安全集合 我们都知道,java中的很多集合,比如:ArrayList、LinkedList、HashMap、HashSet等,都是线程

代码时光 5277

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

继续造轮子吧JS版HashMap

同样的是HashMap的JS版本,网上也有很多,我只是chong'fu

thesadboy的专栏 625

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

不要再重复造轮子了!这17个Java常用工具类,让生产力爆表

当然,这个例子中没有演示MdcUtil类的add方法具体调的地方,我们可以在filter中执行接口方法之前,生成traceId,调用MdcUtil类的add方法添加到MDC中,然后在同一个请求的其他地方就能通过MdcUtil类的get方法获取到该traceId。很多时候,我们会在代码中定义http的返回码,比如:接口正常返回200,异常返回500,接口找不到返回404,接口不可用返回502等。那么该请求的整个过程中,保存到MDC的ThreadLocal中的参数,也是该线程独享的,所以不会有线程安全问题。

IT枫斗者的博客 3711

hashmap 允许key重复吗_HashSet:实不相瞒,我就是个套壳 HashMap

正文开始之前的 7000 字说清楚 HashMap 已经详细介绍了 HashMap 的原理和实现,本次再来说说他的同胞兄弟 HashSet,这两兄弟经常被拿出来一起说,面试的时候,也经常是两者结合着考察。难道它们两个的实现方式很类似吗,不然为什么总是放在一起比较。实际上并不是因为它俩相似,从根本上来说,它俩本来就是同一个东西。再说的清楚明白一点, HashSet 就是个套了壳儿的 HashMap。...

weixin_35850219的博客 740

C语言造轮子实战:从动态字符串到配置解析器

C语言的标准库以轻薄著称,很多高级语言中开箱即用的容器和字符串工具,在C里都需要自己动手实现。这种"造轮子"的过程,是把指针、内存管理和回调函数等底层机制从黑盒变成白盒的有效学习路径。手动实现一个动态字符串库,你会深入理解realloc扩容、野指针规避和倍增策略的工程取舍;而编写一个配置文件解析器,则能串起文件读写、结构体设计、错误处理等完整实践环节。这些看似基础的组件,正是培养工程代码能力和排查内存问题功底的基石,也能让开发者从API使用者转变为底层实现者,真正掌握C语言的核心价值。

weixin_32520095的博客 159

c++ hashset的用法_HashSet:我就是个套壳儿 HashMap

我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面。之前的7000 字说清楚 HashMap已经详细介绍了 HashMap 的原理和实现,本次再来说说他的同胞兄弟 HashSet,这两兄弟经常被拿出来一起说,面试的时候,也经常是两者结合着考察。...

weixin_32228727的博客 2402

java list取差集_Java 取集合的差集,list集合或者map集合,都可以取差集。使用guava工具类来做。而不是重复的造轮子。...

在使用集合的时候,我们有时候需要取两个集合的差集,这两个集合一般是List类型的集合。一般情况下,要是我们自己去造轮子的话 ,那也简单。只是。因人而异,造出来的轮子的质量也是参差不齐。既如此,何不使用别人已经造好的,专业的轮胎呢?下面的代码呢,是我自己实现的取list和map的差集的方法。主要是基于guava工具类的实现。具体看代码吧。package com.lxk.collectionTest;...

weixin_39951396的博客 3143

JDK1.8 HashMap源码解读

JDK1.8 HashMap源码解读写作目的问题合集HashMap的继承与实现HashMap的关键参数HashMap的构造方法HashMap的常见方法 写作目的 本文旨在探究HashMap的源码设计思路,仅供学习交流之用. 问题合集 HashMap的继承与实现 1.问:在JDK1.8中,HashMap的继承与实现的关系如何? 答: 源码如下: public class HashMap<K,V> extends AbstractMap<K,V> implements Map&l

m0_38099524的博客 196

不要再重复造轮子了,这16个Java常用工具类,让生产力爆表。

在java的庞大体系中,其实有很多不错的小工具,也就是我们平常说的:轮子。如果在我们的日常工作当中,能够将这些轮子用户,再配合一下 的快捷键,可以极大得提升我们的开发效率。今天我决定把一些压箱底的小工具,分享给大家,希望对你有所帮助。首先出场的是 包下的 类,该类主要用于操作集合或者返回集合,我个人非常喜欢用它。在工作中经常有对集合排序的需求。看看使用 工具是如何实现升序和降序的: 执行结果: ② 获取最大或最小值 有时候需要找出集合中的最大值或者最小值,这时可以使用 的 和 方法。例如: 执

Always206的博客 1261

c++ hashset的用法_HashSet:实不相瞒,我就是个套壳 HashMap

作者 |风筝公众号:古时的风筝(ID:gushidefengzheng)转载请联系授权之前的7000 字说清楚 HashMap已经详细介绍了 HashMap 的原理和实现,本次再来说说他的同胞兄弟 HashSet。这两兄弟经常被拿出来一起说,面试的时候,也经常是两者结合着考察。难道它们两个的实现方式很类似吗,不然为什么总是放在一起比较。实际上并不是因为它俩相似,从根本上来说,它俩...

weixin_39867200的博客 3144

别再重复造轮子了,推荐使用 Google Guava 开源工具类库,真心强大!

Google Guava 概述 1、Guava 是一组来自 Google 的核心 Java 库,包括新的集合类型(如 multimap 和 multiset)、不可变集合、图形库以及用于并发、I/O、散列、缓存、原语、字符串等的实用程序!被广泛应用于 Google 的大多数 Java 项目中,也被许多其他公司广泛使用。 2、guava github 开源地址:GitHub - google/guava: https://github.com/google/guava 3、官网用户手册 https://

Java技术栈,分享最主流的Java技术 1118

HashMap是什么

网上有篇博文总结得很好,始终贯彻避免重复造轮子,我就直接引用这篇博客了。。。。 原文地址:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table) 也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中HashMap的实...

weixin_43410352的博客 721
上一篇: 深入分析Java Web -- cookie和session
下一篇: HashSet的底层原理
Danny_idea
博客等级 码龄10年 274粉丝 199原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值