Java集合(四)HashMap详解

HashMap简介

java.lang.Object
   ↳     java.util.AbstractMap<K, V>
         ↳     java.util.HashMap<K, V>

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable { }

 

HashMap是一个散列表,存储的是键值对映射。它的实现不是同步的,也就是不是线程安全的。它的key-value可以定为null。同时存储的数据是无序的。
HashMap中有两个参数影响性能:“初始容量”和“加载因子”。容量是HashMap中桶的数量。初始容量是哈希表在创建时的容量,加载因子是哈希表子在容量自动增长之前可以达到多满的一种尺度。当哈希表中的实际数量大于加载容量*当前容量时,需要对HashMap进行resize()。

HashMap源码分析

HashMap源码(JDK6)
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{

    //默认的初始容量
    static final int DEFAULT_INITIAL_CAPACITY = 16;
    //最大容量,如果传入容量多大,将被这个值替换
    static final int MAXIMUM_CAPACITY = 1 << 30;
    //默认加载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //存储数据的Entry数组,长度是2的n次幂。
    transient Entry[] table;

    //HashMap的大小,他是HashMap保存的键值对的数量
    transient int size;

    //阀值,用于判断是否需要调整HashMap的容量,阀值=(容量*加载因子)
    int threshold;

    //加载因子的实际大小
    final float loadFactor;

    //HashMap的改变次数
    transient volatile int modCount;

    //指定容量大小和加载因子的构造函数
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        //找出大于initialCapacity的最小的2的幂
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;

        this.loadFactor = loadFactor;
        //设置阀值
        threshold = (int)(capacity * loadFactor);
        //创建Entry数组,保存数据
        table = new Entry[capacity];
        init();
    }

    //指定容量的构造函数
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    //默认构造函数
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
    }

    //含有子Map的构造函数
    public HashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        putAllForCreate(m);
    }
    //计算hash值(扰动函数)
    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    //返回数组下标,根据hash值和HashMap的长度,计算出下标值
    static int indexFor(int h, int length) {
        return h & (length-1);
    }

    //返回HashMap的大小
    public int size() {
        return size;
    }

    //判断hashMap是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //获取key对应的vaule
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        //获取key的hash值
        int hash = hash(key.hashCode());
        //在该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.equals(k)))
                return e.value;
        }
        return null;
    }

    //获取key为null的元素的值(HashMap将key为Null的元素存储在table[0]上)
    private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }

    //hashMap是否包含Key
    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

    //返回键为key的键值对
    final Entry<K,V> getEntry(Object key) {
        //计算hash值,HashMap将key为Null的元素存储在table[0]的位置,key不为null的需要计算hash值
        int hash = (key == null) ? 0 : hash(key.hashCode());
        //在hash值对应的链表上查找键值=key的元素,先判断hash值是否相等,在判断key是否相等,是因为通过hash判断的效率高
        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;
    }

    //将key-value添加到HashMap中
    public V put(K key, V value) {
        //如果key为Null,将键值对添加到table[0]的位置
        if (key == null)
            return putForNullKey(value);
        //key不为空,计算hash值,根据hash值获取位置索引
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        //遍历链表,判断key对应的值是否存在,存在用新值替代
        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;
            }
        }

        modCount++;
        //键值对不存在,将key-value添加到table中
        addEntry(hash, key, value, i);
        return null;
    }

    //将key为null的添加到table[0]的位置
    private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

    //创建hashMap对应的添加方法,用于内部调用,被构造函数调用创建HashMap,put()用于对外提供添加元素
    private void putForCreate(K key, V value) {
        int hash = (key == null) ? 0 : hash(key.hashCode());
        int i = indexFor(hash, table.length);

        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                e.value = value;
                return;
            }
        }

        createEntry(hash, key, value, i);
    }

    //将m中的元素全都添加到HashMap中
    private void putAllForCreate(Map<? extends K, ? extends V> m) {
        //利用迭代器将元素逐个添加到hashMap中
        for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
            Map.Entry<? extends K, ? extends V> e = i.next();
            putForCreate(e.getKey(), e.getValue());
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值