简单实现jdk1.7HashMap

文章展示了如何定义一个Map接口和实现HashMap类,包括put、get和size方法。HashMap使用Entry对象存储键值对,通过哈希函数确定索引,处理哈希冲突时采用链表。文章还讨论了为何HashMap的容量通常设置为2的幂次方,以保证索引计算效率和冲突分散。
摘要由CSDN通过智能技术生成

 1.定义一个Map接口,Entry<K,V>对象为Map的元素

package test;

public interface Map<K,V> {
    V put(K k,V v);
    V get(K k);
    int size();

    interface Entry<K,V>{
       K getKey();
       V getValue();
    }

}

2.主要实现了put,get以及size()方法

package test;


public class HashMap<K, V> implements Map<K, V> {
    Entry[] table = null;
    int size;

    HashMap() {
        table = new Entry[16];
    }

    /**
     * 1.hashCode(k),算出哈希值
     * 2.取余运算算出index索引值
     * 3.是否有值,如果没有值则添加,有值则添加到链表中
     *
     * @param k
     * @param v
     * @return
     */
    @Override
    public V put(K k, V v) {
        int index = hash(k);
        System.out.println(k.hashCode());
        if (table[index] == null) {
            table[index] = new Entry(k, v, k.hashCode(), null);
            size++;
        } else {
            table[index] = new Entry(k, v, k.hashCode(), table[index]);
        }
        return (V) table[index].getValue();
    }

    private int hash(K k) {
        int i = k.hashCode() % 16;
        return i > 0 ? i : Math.abs(i);
    }

    /**
     * 1.通过k获取到hashCode值
     * 2.算出index
     * 3.判断k是否相等,如果相等则返回,如果不等则判断其他链表是否相等
     *
     * @param k
     * @return
     */
    @Override
    public V get(K k) {
        int hash = hash(k);
        Entry<K, V> entry = table[hash];
        return findValueByKey(entry, k);
    }

    private V findValueByKey(Entry<K, V> entry, K k) {
        if (entry == null) {
            return null;
        }
        if (entry.getKey().equals(k) || k == entry.getKey()) {
            return (V) entry.getValue();
        } else if (entry.next != null) {
            return (V) findValueByKey(entry.next, k);
        }
        return null;
    }

    @Override
    public int size() {
        return size;
    }

    static class Entry<K, V> implements Map.Entry<K, V> {
        K k;
        V v;
        int hashCode;
        Entry<K, V> next;

        public Entry(K k, V v, int hashCode, Entry<K, V> next) {
            this.k = k;
            this.v = v;
            this.hashCode = hashCode;
            this.next = next;
        }

        @Override
        public K getKey() {
            return this.k;
        }

        @Override
        public V getValue() {
            return this.v;
        }
    }
}

3.测试

package test;



public class test {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<String,Object>();
        map.put("lzf", "海淀");
        map.put("zhx", "昌平");
        map.put("wq", "朝阳");
        int size = map.size();
        System.out.println(map.get("lzf"));
        System.out.println(map.get("zhx"));
        System.out.println(map.get("wq"));
        System.out.println("size = " + size);
    }
}

4.结果

 其中"zhx"和"wq"索引值相同出项hash冲突,按照头插法放入链表中.

hashMap和ArrayList其实差不多,arrayList自带索引值,而hashMap是通过算出key的hashCode在通过一系列的位运算得出hash值,hash值^table.length-1得到索引值.

为什么hashMap的容量要是2的幂次方

首先计算键值对的索引要满足两个要求:不能越界、均匀分布

而 h % length (h根据key计算出来的哈希值)就能满足这一点,但是取模运算速度较慢。

容量为2的次幂时、而 h & (length-1)刚好也能满足,而且按位与运算速度很快。

所以最终结果我认为:HashMap容量为2的次幂 开始是为了提高计算索引速度,但在解决哈希冲突过高的过程中通过右移+异或打乱哈希值,使得哈希冲突大大减少

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值