【java集合】自己实现简易的HashMap~改良

来源:互联网 发布:c 高级编程 第7版 pdf 编辑:程序博客网 时间:2024/06/10 02:14

map接口:

public interface IMyMap<K, V> {    V put(K key, V value);    V get(K key);    int size();    interface Entry<K, V>{};}

实现:

import java.util.HashMap;/** * Created by hasee on 2017/11/2. */public class MyHashMap<K, V> implements IMyMap<K, V> {    static final float DEFAULT_LOAD_FACTOR = 0.75f;    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //一定要是2的整数幂    Entry<K, V>[] table;    int size;    final float loadFactor;    int threshold;    public MyHashMap() {        loadFactor = DEFAULT_LOAD_FACTOR;        table = new Entry[DEFAULT_INITIAL_CAPACITY];        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);    }    public MyHashMap(int initialCapacity) {        this(initialCapacity, DEFAULT_LOAD_FACTOR);    }    public MyHashMap(int initialCapacity, float loadFactor) {        this.loadFactor = loadFactor;        int capacity = 1;        while (capacity < initialCapacity)          //使得数组长度一定是2的整数幂            capacity <<= 1;        threshold = (int)(capacity * loadFactor);        table = new Entry[capacity];    }    @Override    public V put(K key, V value) {        int h = hash(key);        int index = indexFor(h, table.length);        //迭代此索引上的所有Entry对象        for (Entry<K, V> e = table[index]; null!=e; e=e.next){            //如果当前e的hash等于计算出来的hash,并且key也等于e的key,那么替换e的value并返回旧值            if (h == e.hash && key.equals(e.key)){                V oldValue = e.value;                e.value = value;                return oldValue;            }        }        //如果索引上还没有对象或索引的链表没有此key,就创建对象        Entry<K, V> e = table[index];        table[index] = new Entry<K, V>(e, value, key, h);        //检测是否需要扩容        if (size++ >= threshold)            doubleSize();        return null;    }    //哈希扰动函数(提高性能的关键)    static final int hash(Object key){//        int h;//        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);        //上面两行是jdk源码,它等价于下面        if(key == null)            return 0;        //获取一个32位的hashCode        int h = key.hashCode();        //无符号右移16位(左边填充0),即如果当前hashCode小于2的16次方,temp就会等于0        int temp = h >>> 16;        /**         * 进行按位异或(XOR)运算,按位异或就是把两个数按二进制,相同就取0,不同就取1。         * 比如:0101 ^ 1110 的结果为 1011         * 任何一个数,与0按位异或的结果都是这个数本身:         * 0 ^ 0 = 0, 1 ^ 0 = 1         * 所以这里的含义是保留高16位,而低16位则会因XOR运算得出不同的数值         * 这样做的好处是:         * 自己的高半区和低半区做异或,就是为了混合原始哈希码的高位和低位,以此来加大低位的随机性         * 从而降低哈希冲突         * */        int newHash = h ^ temp;        return newHash;    }    /**     * 这里正好解释了数组长度为什么一定要是2的整次幂     * 因为这样数组长度-1刚好能成为一个低位掩码     * 任何数与数组长度-1做与运算,相当于做取模(%)运算,不过会比%运算效率高     * 例如数组长度为16,那么18和16的模相当于18 & (16-1)     * 0001 0010 & 0000 1111 = 0000 0010 = 十进制的2     */    static final int indexFor(int hash, int tableLength){        return hash & (tableLength - 1);    }    //扩容为原来的两倍    final void doubleSize(){        int newCapacity = table.length << 1;        Entry<K, V>[] newTable = new Entry[newCapacity];        threshold = (int)(newCapacity * loadFactor);        //需要再散列        hashAgain(newTable);        table = newTable;    }    //再散列    final void hashAgain(Entry<K, V>[] newTable){        Entry<K, V>[] source = table;        int newCapacity = newTable.length;        for (int i=0; i<source.length; i++){            Entry<K, V> e = source[i];            if (null != e){                source[i] = null;                do {                    Entry<K, V> next = e.next;                    int index = indexFor(e.hash, newCapacity);                    e.next = newTable[index];                    newTable[index] = e;                    e = next;                } while (null != e);            }        }    }    @Override    public V get(K key) {        int index = indexFor(hash(key), table.length);        int hash = hash(key);        Entry<K, V> e = table[index];        while (null != e){            if (hash == e.hash && (e.key == key || key.equals(e.key)) )                return e.value;            e = e.next;        }        return null;    }    @Override    public int size() {        return size;    }    private static class Entry<K, V> implements IMyMap.Entry{        Entry<K, V> next;        V value;        final K key;        final int hash;        public Entry(Entry<K, V> next, V value, K key, int hash) {            this.next = next;            this.value = value;            this.key = key;            this.hash = hash;        }    }}


原创粉丝点击