美文网首页
HashMap的深度解析

HashMap的深度解析

作者: 飘絮无意 | 来源:发表于2020-04-07 16:15 被阅读0次

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中的对应实现HashMap的实现原理进行讲解,然后会对JDK7的HashMap源码进行分析。

    在了解hashMap我们先了解几个面试会遇到的问题:

    1.HashMap存储键值对实现快速存取,允许为null。key值不可重复,若key值重复则覆盖。

    2.非同步,线程不安全。

    3.底层是hash表,不保证有序(比如插入的顺序

    4.hash值相等,两个对象不一定相等;两个对象不相同,hash值可能相同;

    5.hashMap数据结构是数组+单链表,扩容因子为0.75 过大导致数据过于密集 查询速度降低 过小扩容频繁 浪费内存

    put过程:

    1、执行hash(Object key)得到hash值,根据 hash 值找到其所在的数组的角标位置index

    2、再去遍历该桶里面的链表判断是否有 key 相同,如果有则覆盖

    3、key不同则产生hash碰撞 需要将值插入到链表里面

    4、在插入值之前需要首先需要判断是否进行扩容(1.8里面先插入再扩容)插入这个值是否导致size已经超过了阈值,是则进行扩容

    为加深印象先看看结构图

    image

    下面是我自己撸的一个散列表 逻辑思想基本跟hasnMap一样 里面有put方法get方法 和resize扩容方法

    
    public class HashMapTest<K,V> {
    
      private MapEntry[] table;
    
      //存放大小
    
      transient int size;
    
      //扩容阀值
    
      int threshold=8;
    
      //扩容因子
    
      float  LOADFACTOR= 0.75f;
    
    class MapEntry<K,V>{
    
    K key;
    
    V value;
    
    MapEntry<K,V> next;
    
    int hash;
    
    public MapEntry(int hash,K key, V value,MapEntry<K,V> next) {
    
    super();
    
    this.hash=hash;
    
    this.key = key;
    
    this.value = value;
    
    this.next=next;
    
    }
    
    }
    
    public V put(K key,V value) {
    
    if (table==null) {
    
    table=new MapEntry[8];
    
    }
    
    if (key==null) {
    
    return null;
    
    }
    
    int hash=hash(key);
    
    int index=getIndex(hash,table.length);
    
    for (MapEntry<K,V> e =table[index];e!=null;e=e.next) {
    
    Object obj ;
    
    if (e.hash==hash && ((obj=e.key)==key || obj.equals(key)) ) {
    
    V oldValue=e.value;
    
    e.value= value;
    
    return oldValue;
    
    }
    
    }
    
    addEntry(hash,key,value,index);
    
    return null;
    
    }
    
    public V get(K key) {
    
    if (key==null) {
    
    return null;
    
    }
    
    MapEntry<K, V> entry= getEntry(key);
    
    return entry==null ? null :entry.value;
    
    }
    
    private MapEntry<K, V> getEntry(K key) {
    
    int hash=hash(key);
    
    int index=getIndex(hash,table.length);
    
    for (MapEntry<K,V> e =table[index];e!=null;e=e.next) {
    
    Object obj ;
    
    if (e.hash==hash && ((obj=e.key)==key || obj.equals(key) )) {
    
    return e;
    
    }
    
    }
    
    return null;
    
    }
    
    private void addEntry(int hash, K key, V value, int index) {
    
    //1.先判断是否扩容
    
    if (size >= threshold && table[index]!=null) {
    
    System.out.println("kuo");
    
    //扩容一倍
    
    resize(size << 1);
    
    index=getIndex(hash, table.length);
    
    }
    
    createEntry(hash,key,value,index);
    
    }
    
    private void resize(int newCapcity) {
    
    MapEntry<K,V> [] newTable =new MapEntry[newCapcity];
    
    transform(newTable);
    
    table=newTable;
    
    threshold= (int) (newCapcity * LOADFACTOR) ;
    
    }
    
    private void transform(MapEntry<K,V>[] newTable) {
    
    int capcity=newTable.length;
    
    for (MapEntry<K,V> e : table) {
    
    while (null!=e) {
    
    MapEntry<K,V> next = e.next;
    
    int index = getIndex(e.hash,capcity);
    
    e.next=newTable[index];
    
    newTable[index]=e;
    
    e=next;
    
    }
    
    }
    
    }
    
    private void createEntry(int hash, K key, V value, int index) {
    
    MapEntry<K, V> entry=new MapEntry<>(hash, key, value, table[index]);
    
    table[index]=entry;
    
    size++;
    
    }
    
    private int getIndex(int hash,int length) {
    
    //降低时间复杂度 更散
    
    return hash & length -1;
    
    }
    
    private int hash(K key) {
    
    int h = 0;
    
    return (key==null) ? 0:(h=key.hashCode() ^ (h >>>16));
    
    }
    
    public int  getTableSize() {
    
    return table.length;
    
    }
    
    }
    
    

    以上代码仅供参考 有不对的地方请批评指定

    相关文章

      网友评论

          本文标题:HashMap的深度解析

          本文链接:https://www.haomeiwen.com/subject/qiynphtx.html