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

自己实现HashMap-通俗易懂

前言HashMap的底层实现主要是基于数组和链表来实现的,HashMap中通过key的hashCode来计算hash值的,由这个hash值计算在数组中的位置,将新插入的元素放到数组

前言

HashMap的底层实现主要是基于数组和链表来实现的,HashMap中通过key的hashCode来计算hash值的,由这个hash值计算在数组中的位置,将新插入的元素放到数组的这个位置,如果新插入的元素的hash值跟这个位置上已有元素的hash值相同,就会出现hash冲突,这时候,就在该位置通过链表来插入新的元素。
参考图:http://www.cnblogs.com/chengxiao/p/6059914.html
这里写图片描述


代码实现

  1. MyMap接口
  2. MyHashMap实现类
  3. MyHashMapTest测试类

1)MyMap接口

package com.cxx.map.HashMap;
/** * @Author: cxx * 自己实现 map接口 * @Date: 2018/6/8 11:18 */
public interface MyMap<K,V> {
    //大小
    int size();
    //是否为空
    boolean isEmpty();
    //根据key获取元素
    Object get(Object key);
    //添加元素
    Object put(Object key,Object value);
    interface Entry{
        k getkey();
        v getValue();
    }
}

2)MyHashMap实现类

package com.cxx.map.HashMap;
import java.util.Map;
import java.util.Set;
/** * @Author: cxx * 自己实现HashMap * 底层结构:数组+链表 * @Date: 2018/6/8 11:30 */
public class MyHashMap<K,V> implements MyMap {
    //默认容量16
    private final int DEFALUT_CAPACITY=16;
    //内部存储结构
    Node[] table = new Node[DEFALUT_CAPACITY];
    //长度
    private int size=0;
    //keySet
    Set keySet;
    @Override
    public int size() {
        return this.size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public Object get(Object key) {
        int hashValue = hash(key);
        int i=indexFor(hashValue,table.length);
        for (Node node=table[i];node!=null;node=node.next){
            if (node.key.equals(key)&&hashValue==node.hash){
                return node.value;
            }
        }
        return null;
    }

    @Override
    public Object put(Object key, Object value) {
        //通过key,求hash值
        int hashValue=hash(key);
        //通过hash,找到这个key应该放的位置
        int i=indexFor(hashValue,table.length);
        //i位置已经有数据了,往链表添加元素
        for (Node node=table[i];node!=null;node=node.next){
            Object k;
            //且数组中有这个key,覆盖其value
            if (node.hash==hashValue&&((k=node.key)==key||key.equals(k))){
                Object oldValue=node.value;
                node.value=value;
                //返回oldValue
                return oldValue;
            }
        }
        //如果i位置没有数据,或i位置有数据,但key是新的key,新增节点
        addEntry(key,value,hashValue,i);
        return null;
    }

    public void addEntry(Object key,Object value,int hashValue,int i){
        //如果超过了原数组大小,则扩大数组
        if (++size==table.length){
            Node[] newTable=new Node[table.length*2];
            System.arraycopy(table,0,newTable,0,table.length);
            table=newTable;
        }
        //的到i位置的数据
        Node eNode=table[i];
        //新增节点,将该节点的next指向前一个节点
        table[i]=new Node(hashValue,key,value,eNode);
    }

    //获取插入的位置
    public int indexFor(int hashValue,int length){
        return hashValue%length;
    }
    //获取hash值
    public int hash(Object key){
        return key.hashCode();
    }

    //静态内部类:Node节点实现Entry接口
    static class Node implements MyMap.Entry{
        int hash;//hash值
        Object key;//key
        Object value;//value
        Node next;//指向下个节点(单例表)
        Node(int hash,Object key,Object value,Node next){
            this.hash=hash;
            this.key=key;
            this.value=value;
            this.next=next;
        }
        @Override
        public Object getkey() {
            return this.key;
        }

        @Override
        public Object getValue() {
            return this.value;
        }
    }
}

3)MyHashMapTest测试类

package com.cxx.map.HashMap;
import java.util.HashMap;
import java.util.Map;
/** * @Author: cxx * @Date: 2018/6/8 11:41 */
public class TestMap {
    public static void main(String[] args) {
        MyMap map = new MyHashMap();
        map.put("a1",1);
        map.put("a2",2);
        System.out.println("size:"+map.size());
        System.out.println("isEmpty:"+map.isEmpty());
        System.out.println(map.get("a1"));
    }
}

这里写图片描述


总结

简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。


推荐阅读
  • 转载自:http:www.blogjava.netCarpenterLeearchive20160427430268.html总体介绍之所以把HashSet和HashMa ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的。LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉。先说说List:每 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • Java集合详解5:深入理解LinkedHashMap和LRU缓存
    Java集合详解5:深入理解LinkedHashMap和LRU缓存今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存。具体代码在我的 ... [详细]
  • 本篇文章给大家分享的是有关Java中怎么对HashMap按键值排序,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话 ... [详细]
  • 将学生对象和学生的归属地通过键与值存储到map集合中。importjava.util.HashMap;importjava.util.Iterator;importjava.uti ... [详细]
  • 01Map集合概述A:Map集合概述:我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同a:Collection中的集合 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
author-avatar
亲爱的常青藤先生
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有