HashMap的实现原理以及如何自己写一个HashMap

在面试的过程中,很多面试官会问Hashmap的实现原理,进而又会问你能自己实现一个HashMap吗?在看jdk1.7的源码时,源码代码比较冗余,具体体现在key==null的处理

一下时具体的讲解

以下是HashMap的实现原理

  •   创建一个HashMap,初始化容量,负载比例
  •   然后对于put操作

    1. 刚开始put时候对于数组table是空的,所以样创建一个table的数组,其元素类型是静态类Entry类型包含key,value,next,

      以及key的hash

    2.获得key的hash值 hash=hash(key)

    3.获取BucketIndex i=hash & table.length-1
    4.循环遍历 table[i]下的entry看key是否存在,if(key==e.key || key.equals(key)),循环的结束条件e!=null
    5.如果在循环体发现存在相同的key,那么直接新值替换旧值,然后返回旧值
    6.添加值
        1.如果整个的hashmap值的大小 size >= threshold
        则重新resize(2*table.length),里面伴随着rehash
        并且重新hash=hash(key),bucketIndex
        
        2.拿到第一个entry e=table[bucketIndex]
        3.table[bucketIndex]=new Entry(hash,key,value,e)
        采用的是链表的头插法,避免尾指针遍历,size++
        需要注意的是如果key==null 则 hash=0  bucketIndex=0,key=null ,相当于table[0]    

 7.get方法的总结:
    1.传入一个key
    2.如果key==null,其hash值为0,而且bucketIndex=0
    3.循环遍历e=table[bucketIndex],e!=null,e.next.if(hash==e.hash)&& (key==e.key || (key!=null && key.equals(e.key))
    return e  循环结束之后则返回 null  , 
    4.如果返回的entry为null则返回null 否则则返回 e.value

源码解析:

put操作:
    
      if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }    
        
        private void inflateTable(int toSize) {
        // Find a power of 2 >= toSize
        int capacity = roundUpToPowerOf2(toSize);

        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
        table = new Entry[capacity];
        initHashSeedAsNeeded(capacity);
    }
put:
 if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);    
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        
        }
        
 void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }
    
    
void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }
get方法解析:

 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }
    
   private V getForNullKey() {
        if (size == 0) {
            return null;
        }
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }    
    
     final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }

        int hash = (key == null) ? 0 : hash(key);
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

上面是java1.7的源代吗?写的不好对于key的判断,代码的冗余量太大
就是对于key是否为null的处理

面试官可能让你自己实现一个hashmap,简单的实现方式如

 

public class MyHashMap<K,V> {

    private int capacity;

    private Entry[] table;
    private int size;
    static class Entry<K,V>{
        int hash;
        K key;
        V value;
        Entry<K,V> next;
        public Entry(int hash, K key, V value, Entry<K,V> next) {
            super();
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }
    
    
    public MyHashMap(int capacity) {
        super();
        this.capacity = capacity;
        size=0;
        table=new Entry[capacity];
    }
    
    public V get(K key){
        int hash;
        if(key==null){
            hash=0;
        }else{
            hash=hash(key);
        }
        Entry<K, V> entry=null;
        int bucketIndex= tableIndex(hash,table.length);
        for(Entry<K, V> e=table[bucketIndex]; e !=null; e=e.next){
            if(key==e.key || (key!=null && key.equals(e.key))){
              entry=e;
              break;
            }
            
        }
        
        return entry ==null ? null : entry.value;
    }
    
    public V put(K key,V value){
        int hash;
        if(key==null) hash=0; else hash=hash(key);
        int bucketIndex= tableIndex(hash,table.length);
        
        for(Entry<K, V> e=table[bucketIndex]; e !=null; e=e.next){
            if(key==e.key || (key!=null && key.equals(e.key))){
                V oldValue=e.value;
                e.value=value;
                return oldValue;
            }
            
        }
        createEntry(hash,key,value,bucketIndex);
        return null;
    }
    
    private void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K, V> old=table[bucketIndex];
        table[bucketIndex]=new Entry<K, V>(hash, key, value, old);
        size++;
    }


    private int tableIndex(int hash, int length) {
        return hash & length-1;
    }


    final int hash(Object k) {
        return k.hashCode();
    }
    
    
    public static void main(String[] args) {
        MyHashMap<Integer, Integer> my=new MyHashMap<>(16);
        my.put(1, 3);
        my.put(1, 4);
        my.put(2, 6);
        my.put(null, 6);
        my.put(null, 7);
        System.out.println(my.get(1));
        System.out.println(my.get(2));
        System.out.println(my.get(null));
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值