记录学习的点滴(HashMap)

一、HashMap、Hashtable

1.HashMap的key和value可以为null,而Hashtable则不可以。

2.HashMap是非synchronized,而Hashtable是synchronized的。也就是说Hashtable是线程安全的,多个线程可以共享同个Hashtable。如果没有正确同步的话,多个线程不能共享HashMap。Java5之后提供ConcurrentHashMap,替代Hashtable,比Hashtable更好的扩展性。

3.在单线程下,HashMap的性能要优于Hashtable。因为Hashtable是使用synchronized的,所有线程竞争同一把锁。

二、HashMap的工作原理

HashMap实际上是链表散列的数据结构,即数组和链表的结合体。我们可以理解为HashMap底层是数组结构,数组中的每一项是一个链表。

1、HashMap的存储

    public V put(K key, V value) {
        //HashMap允许存储一个null键和多个null值
        //空数组的话,初始化数组容量,初始化长度为16
        //static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        // 当key为null,将它放在数组的第一个位置
        if (key == null)
            return putForNullKey(value);
        // 根据key的keyCode重新计算hash值。
        int hash = hash(key);
        // 搜索指定hash值在对应table中的索引。
        int i = indexFor(hash, table.length);
        // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。
        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;
            }
        }
        // 如果i索引处的Entry为null,表明此处还没有Entry。
        modCount++;
        // 将key、value添加到i索引处。
        addEntry(hash, key, value, i);
        return null;
    }

从上面代码我们可以看出当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

2、HashMap的读取

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

        return null == entry ? null : entry.getValue();
    }
    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;
    }

从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。

3、HashMap的扩容

static final float DEFAULT_LOAD_FACTOR = 0.75f;

// 初始化HashMap的长度

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

当HashMap的元素个数大于16*0.75=12的时候,就把数组的大小扩展为2*16=32,及扩容一倍。然后重新计算每个元素在数组中的位置,这是非常消耗性能的操作。所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值