HashMap源码实现

HashMap存储格式

首先来看看HashMap的数据存储格式:
这里写图片描述

从本质上来说,hashMap实际上是一个数组,数组的每个元素称为一个Node,这个Node实际上是一个链表,每个对象的hash值经过一些处理作为数组的key,hashMap通过key定位到数组对应的位置。当两个对象的hash值相同的时候,就会在链表的next元素进行拓展。

源码

本文主要要实现hashMap的put、get、扩容方法;
基本代码架构:

public class MyHashMap<K,V> {
    //数组的初始大小
    static final int DEFAULR_INITIAL_CAPACITY=16;
    //安全因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //扩容因子
    static final int DEFAULT_DITATATION_FACROT=2;
    private int size = 0;
    //数组元素
    private Node<K,V> table[] = null;
    public V put(){
        return null;
    };
    public V get(){
        return null;
    }
    //Map的大小
    public int size(){
        return this.size;
    }
    //提供hash算法,确定Node在数组中的位置
    private int indexOf(Object o){
        return 0;
    }
    //扩容方法
    private void dilatation() { 
    }
    public class Node<K,V> implements Entry<K, V>{
        @Override
        public K getKey() {
            return null;
        }
        @Override
        public V getValue() {
            return null;
        }
        @Override
        public V setValue(V value) {
            return null;
        }
    }
}

关于构造

前面已经说过,数组的元素是由节点Node

private class Node<K,V> implements Entry<K, V>{
        //Node在数组中的位置,根据对象的hash值确定
        private int index;
        private K key;
        private V value;
        //当hash值出现冲突以后,往链表中插入对象
        private Node<K,V> next;

        public Node(int index, K key, V value, Node<K, V> next) {
            super();
            this.index = index;
            this.key = key;
            this.value = value;
            this.next = next;
        }
        @Override
        public K getKey() {
            return null;
        }
        @Override
        public V getValue() {
            return null;
        }
        @Override
        public V setValue(V value) {
            return null;
        }
    }

下面来看看HashMap的构造:

private Node<K,V> table[] = null;
    //创建一个大小为默认值的数组
    public MyHashMap() {
        table = new Node[DEFAULR_INITIAL_CAPACITY];
    }

hash算法indexOf方法实现:

//提供hash算法,确定Node在数组中的位置
    public int indexOf(K  key){
        //与数组length-1取模,确定返回值不大于数组的length-1
        return hash(key) % (table.length-1);
    }
    //让hash值无符号右移16位,缩小hash值
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

源码实现

put方法实现:

public V put(K key,V value){
        //tab用来指向table,p当前数组位置的Node;
        Node<K, V> tab[] = table; 
        Node<K,V> p;
        int i = indexOf(key);
        p = table[i];
        if(p == null){
            //如果数组的该位置没有元素
            p = new Node<K, V>(i, key, value, null);
            tab[i] = p;
            return value;
        }else{
            //如果数组的该位置有元素
            Node<K,V> e;//用于判断key是否相同,是否需要覆盖
            if(p.index == indexOf(key)&&(p.key==key||key.equals(p.key))){
                //key相同(这里我们可以看到map判断key是否相同需要他的hash值和equals都相同)
                e = p;
            }else{
                //对p进行遍历
                for(int count = 0 ; ; ++count){
                    if((e=p.next)==null){
                        //如果p链表没有后续元素
                        p.next = new Node<K,V>(indexOf(key), key, value, null);
                        break;
                    }
                    //如果链表中其他元素的key有相同的
                    if(e.index==indexOf(key)&&(e.key==key||e.key.equals(key))){
                        break;
                    }
                    //如果链表有后续元素,并且key和链表当前位置的元素key不用,将p指向p.next
                    p= e;
                }
            }
            //key有覆盖的情况出现,将key对应的value进行覆盖处理
            if(e!=null){
                e.value = value;
                return value;
            }
            //e==null则没有覆盖情况
            size++;
            if(size>DEFAULR_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR){
                //扩容;
                dilatation();
            }
        }
        return value;
    };

get方法实现:

public V get(K key){
        Node<K,V> tab[] ; Node<K,V> e ;
        tab = table;
        int index = indexOf(key);
        e = tab[index];
        //该key没有值
        if(e == null){
            return null;
        }else{
            //遍历Node e
            do {
                //获取e的值
                if(key==e.key||key.equals(e.key)){
                    return e.value;
                }
            } while ((e=e.next)!=null);
        }
        return null;
    }

扩容方法dilatation

    //扩容方法
    private void dilatation() {
        Node<K, V> oldNode[] = table;
        int oldCount = table.length;
        //将容量扩张到两倍
        int newCount = oldCount*DEFAULT_DITATATION_FACROT;
        Node<K, V> newNode[] = new Node[newCount];
        table = newNode;
        for(int i = 0 ; i < oldCount ; i++){
            if(oldNode[i]!=null){
                Node<K,V> e = oldNode[i];
                Node<K,V> tmp = oldNode[i];
                //给newNode赋值,修改Node的index值
                int newIndex = indexOf(tmp.getKey());
                do {
                    tmp.index = newIndex;
                } while ((tmp=tmp.next)!=null);
                newNode[newIndex] = e;
            }
        }

    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值