HashMap 原理探索

HashMap就是Hash表的Map实现。 Hash表就是Hash数组,Map实现是指实现了Map接口。


HashMap的底层是基于数组和链表实现的,存储速度快的原因是因为它是通过计算散列码来决定存储的位置。HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的

HashMap其实就是一个Entry数组Entry对象中包含了键和值,其中next也是一个Entry对象,它就是用来处理hash冲突的,形成一个链表。

HashMap存放数据的时候,会先拿到key的hashCode值,对其进行hash运算,得到具体的hash值,然后根据hash值查找存放的位置index,找到存放的位置后,然后遍历table数组找到对应位置的entry,如果当前的key已经存在,且对比entry的hash值和key相同的话,那么就更新value值(在解决hash冲突的链表中,老的数据在链表的末端,端。),否则就将key和value值加到数组中。

hashmap原理视频:

http://www.365yg.com/group/6373149433093701890/iid=7924224675&app=news_article&tt_from=mobile_qq&utm_source=mobile_qq&utm_medium=toutiao_android&utm_campaign=client_share

视频中的源码(仿照hashmap的原理实现的源码):

仿照Map实现:

package com.dongnao.jack;

public interface DNMap<K, V> {
    
    public V put(K k, V v);
    
    public V get(K k);
    
    public int size();
    
    public interface Entry<K, V> {
        public K getKey();
        
        public V getValue();
    }
}
仿照HashMap实现:

package com.dongnao.jack;

import java.util.ArrayList;
import java.util.List;

public class DNHashMap<K, V> implements DNMap<K, V> {
    
    private static int defaultLength = 16;
    
    private static double defaultLoader = 0.75;
    
    private Entry<K, V>[] table = null;
    
    private int size = 0;
    
    public DNHashMap(int length, double loader) {
        defaultLength = length;
        defaultLoader = loader;
        
        table = new Entry[defaultLength];
    }
    
    public DNHashMap() {
        this(defaultLength, defaultLoader);
    }
    
    public V put(K k, V v) {
        
        //在这里要判断一下,size是否达到了一个扩容的一个标准
        if (size >= defaultLength * defaultLoader) {
            up2size();
        }
        
        //1、   创建一个hash函数,根据key和hash函数算出数组下标
        int index = getIndex(k);
        
        Entry<K, V> entry = table[index];
        
        if (entry == null) {
            //如果entry为null,说明table的index位置上没有元素
            table[index] = newEntry(k, v, null);
            size++;
        }
        else {
            //如果index位置不为空,说明index位置有元素,那么就要进行一个替换,然后next指针指向老数据
            table[index] = newEntry(k, v, entry);
        }
        return table[index].getValue();
    }
    
    private void up2size() {
        Entry<K, V>[] newTable = new Entry[2 * defaultLength];
        
        //新创建数组以后,以前老数组里面的元素要对新数组进行再散列
        againHash(newTable);
    }
    
    //新创建数组以后,以前老数组里面的元素要对新数组进行再散列
    private void againHash(Entry<K, V>[] newTable) {
        
        List<Entry<K, V>> list = new ArrayList<Entry<K, V>>();
        
        for (int i = 0; i < table.length; i++) {
            if (table[i] == null) {
                continue;
            }
            findEntryByNext(table[i], list);
        }
        
        if (list.size() > 0) {
            //要进行一个新数组的再散列
            size = 0;
            defaultLength = defaultLength * 2;
            table = newTable;
            
            for (Entry<K, V> entry : list) {
                if (entry.next != null) {
                    entry.next = null;
                }
                put(entry.getKey(), entry.getValue());
            }
        }
    }
    
    private void findEntryByNext(Entry<K, V> entry, List<Entry<K, V>> list) {
        
        if (entry != null && entry.next != null) {
            list.add(entry);
            findEntryByNext(entry.next, list);
        }
        else {
            list.add(entry);
        }
    }
    
    private Entry<K, V> newEntry(K k, V v, Entry<K, V> next) {
        return new Entry(k, v, next);
    }
    
    private int getIndex(K k) {
        
        int m = defaultLength;
        
        int index = k.hashCode() % m;
        
        return index >= 0 ? index : -index;
    }
    
    public V get(K k) {
        
        //1、   创建一个hash函数,根据key和hash函数算出数组下标
        int index = getIndex(k);
        
        if (table[index] == null) {
            return null;
        }
        
        return findValueByEqualKey(k, table[index]);
    }
    
    public V findValueByEqualKey(K k, Entry<K, V> entry) {
        
        if (k == entry.getKey() || k.equals(entry.getKey())) {
            return entry.getValue();
        }
        else {
            if (entry.next != null) {
                return findValueByEqualKey(k, entry.next);
            }
        }
        
        return null;
    }
    
    public int size() {
        return size;
    }
    
    class Entry<K, V> implements DNMap.Entry<K, V> {
        
        K k;
        
        V v;
        
        Entry<K, V> next;
        
        public Entry(K k, V v, Entry<K, V> next) {
            this.k = k;
            this.v = v;
            this.next = next;
        }
        
        public K getKey() {
            return k;
        }
        
        public V getValue() {
            return v;
        }
        
    }
}
测试类:

package com.dongnao.jack;

public class Test {
    
    public static void main(String[] args) {
        DNMap<String, String> dnmap = new DNHashMap<String, String>();
        
        Long t1 = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            dnmap.put("key" + i, "value" + i);
        }
        
        for (int i = 0; i < 10000; i++) {
            System.out.println("key: " + "key" + i + "  value:"
                    + dnmap.get("key" + i));
        }
        Long t2 = System.currentTimeMillis();
        //        System.out.println("jack写的dnhashMap耗时:" + (t2 - t1));
        //        System.out.println("-----------------------HashMap--------------------------");
        //        
        //        Map<String, String> map = new HashMap<String, String>();
        //        Long t3 = System.currentTimeMillis();
        //        for (int i = 0; i < 1000; i++) {
        //            map.put("key" + i, "value" + i);
        //        }
        //        
        //        for (int i = 0; i < 1000; i++) {
        //            System.out.println("key: " + "key" + i + "  value:"
        //                    + map.get("key" + i));
        //        }
        //        Long t4 = System.currentTimeMillis();
        //        System.out.println("jdk的hashMap耗时:" + (t4 - t3));
    }
    
}
参考资料:

HashMap原理和代码浅析:http://blog.csdn.net/u011060103/article/details/51355763



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值