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

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;
        }

    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值