HashMap为什么效率高?来看看这个小demo

一、前情回顾:在程序中有时候需要存放对象,容器应运而生。容器分为集合和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());
    }
}
原文地址:https://www.cnblogs.com/xiaoao/p/11157493.html