HashMap源码解析

最近看了下HashMap的源码,来记录下它的实现原理。
HashMap最一开始是一个基于链表的数组结构,数组的每一个索引位置上都链着具有相同hash计算结果的键值对数据,为了提高查找效率,jdk1.8以后当数组某个索引位置的节点数大于8时,会自动转换为红黑树。
首先要了解HashMap的静态内部类Node<K,V>,即数组索引位置上的链表节点,它继承自Map.Entry<K,V>,也就是我们经常遍历Map时用到的对象类型,储存了Key和Value的值,存入HashMap里的键值对都是以该对象类型存在。

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

还有树节点TreeNode<K,V>,当数组某索引上的键值对数量大于8时会转换为红黑树数据结构,里有很多维持红黑树数据结构的方法,这里不做阐述,想了解的同学可以先去学习红黑树再来看这个结构,会更快理解.

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }
        //......省略很多方法
 }

接着看看HashMap的成员变量:

	 /**
     * 序列号,序列化时使用
     */
	 private static final long serialVersionUID = 362498820763181265L;

    /**
     * 数组默认容量是16,这里使用移位算法是因为移位是计算机基础运算,效率比加减乘除快
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * 最大容量
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 默认加载因子,用于判断是否扩容
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * 当某个桶的节点数大于8时,会转换为红黑树
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * 当某个桶的节点数小于6时,会从红黑树又转换为链表
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * 当hashmap中的元素数量大于64时,也会转换为红黑树
     */
    static final int MIN_TREEIFY_CAPACITY = 64;
	
	 /**
     * 存储键值对元素的数组,也是HashMap结构的核心
     */
	 transient Node<K,V>[] table;

    /**
     * 将键值对数据包装成Set结构,用于遍历
     */
    transient Set<Map.Entry<K,V>> entrySet;

    /**
     * hashmap内存储的元素数量
     */
    transient int size;

    /**
     * hashmap的修改次数
     */
    transient int modCount;

    /**
     * 当元素数量达到此临界值时会进行扩容
     */
    int threshold;

    /**
     * 也是加载因子
     */
    final float loadFactor;

HashMap的构造方法主要围绕数组容量和加载因子的:

	/**
     * 设置初始容量和加载因子
     */
    public HashMap(int initialCapacity, float loadFactor) {
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HashMap是Java中常用的数据结构,用于存储键值对,并支持O(1)时间复杂度的插入、查询、删除等操作。 HashMap源码解析如下: 1. HashMap是一个实现了Map接口的类,内部使用数组和链表实现。 2. HashMap中的键值对是以Entry对象的形式存储的,每个Entry对象包含一个键、一个值和指向下一个Entry对象的引用。 3. HashMap内部维护了一个默认容量为16的数组table,负载因子为0.75,默认扩容因子为2。当HashMap中的元素数量超过容量与负载因子的乘积时,即会触发扩容操作。 4. HashMap使用哈希函数将键映射到对应的数组下标上,实现快速查询。 5. 如果哈希函数产生了哈希冲突,即多个键映射到同一个数组下标上,HashMap会使用链表将这些键值对串起来,以便查询时遍历链表查找。 6. 在插入新的键值对时,HashMap会根据哈希函数计算出对应的数组下标,并将新的键值对插入到该位置的链表中。如果该位置的链表长度超过阈值(默认为8),则将这个链表转化为红黑树,以提高查询效率。 7. 在查询、删除键值对时,HashMap根据哈希函数计算出对应的数组下标,并遍历该位置的链表或红黑树,查找对应的键值对。如果链表或红黑树中没有对应的键值对,则返回null。 总之,HashMap是一个高效的数据结构,能够快速地插入、查询、删除键值对。不过,对于高度散列的数据集,也可能导致哈希冲突的增加,进而导致查询效率下降。因此,在使用HashMap时,需要合理地设置容量和负载因子,以及注意键的哈希函数的设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值