Java集合深入学习 - HashMap源码解析-1基础(基于jdk1.8)

Java集合深入学习 - HashMap源码解析-1基础(基于jdk1.8)

Java集合深入学习 - HashMap源码解析-2查找数据(基于jdk1.8)

Java集合深入学习 - HashMap源码解析-3添加与扩容(基于jdk1.8)

Java集合深入学习 - HashMap源码解析-4删改与遍历(基于jdk1.8)

 

 

1.类的定义

话不多说,还是直接上代码

/**
 * AbstractMap 	抽象Map
 * Map Map		接口
 * Cloneable	克隆
 * Serializable	序列化
 */
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {}

/**
 * 抽象Map类   实现了Map接口的部分方法
 */
public abstract class AbstractMap<K,V> implements Map<K,V> {}

/**
 * Map接口
 */
public interface Map<K,V> {}

2.属性,节点与构造方法

2.1 HashMap的各个属性解释

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

    private static final long serialVersionUID = 362498820763181265L;


    /**
     * 默认初始容量 
     */
    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;

    /**
     * 桶的树化阈值:即 链表转成红黑树的阈值,在存储数据时,当链表长度 > 该值时,则将链表转换成红黑树
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * 桶的链表还原阈值:即 红黑树转为链表的阈值,当在扩容(resize())时(此时HashMap的数据存储位置会重新计算),在重新计算存储位置后,当原有的红黑树内数量 < 6时,则将 红黑树转换成链表
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * 最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即 将链表 转换成红黑树)
     * 否则,若桶内元素太多时,则直接扩容,而不是树形化
     * 为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD
     */
    static final int MIN_TREEIFY_CAPACITY = 64;

    /**
     * 节点数组 
     */
    transient Node<K,V>[] table;

    /**
     * HashMap将数据转换成set的另一种存储形式,这个变量主要用于迭代功能。
     */
    transient Set<Map.Entry<K,V>> entrySet;

    /**
     * HashMap中实际存在的Node数量,注意这个数量不等于table的长度,因为在table的每个节点上是一个链表(或RBT)结构,可能不止有一个Node元素存在。
     */
    transient int size;

    /**
     * 操作次数
     */
    transient int modCount;

    /**
     * HashMap的扩容阈值,在HashMap中存储的Node键值对超过这个数量时,自动扩容容量为原来的二倍。
     */
    int threshold;

    /**
     * HashMap的负载因子,可计算出当前table长度下的扩容阈值:threshold = loadFactor * table.length。 
     */
    final float loadFactor;
}

2.2 HashMap的节点定义

    /**
     * HashMap节点定义 实现Map中的Entry
     * 	--链表节点
     */
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;	//hash值
        final K key;	//key
        V value;	//value值
        Node<K,V> next;	//下一个节点
    }

    /**
     * Map接口中的节点接口定义
     */
    interface Entry<K,V> {}

    /**
     * HashMap的节点定义 继承LinkedHashMap中的Entry
     * --红黑树的节点
     */
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  	//父节点
        TreeNode<K,V> left;		//左子节点
        TreeNode<K,V> right;	//右子节点
        TreeNode<K,V> prev;    	//上一个节点(与父类中的next一起使用)
        boolean red;			//记录树的颜色
    }

    /**
     * LinkedHashMap定义的Entry 继承自HashMap中Node节点类
     */
    static class Entry<K,V> extends HashMap.Node<K,V> {
        /**
         * before,before分别指向前一个节点与后一个节点
         */
    	Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

2.3 HashMap的构造方法

    /**
     * 初始化方法传入参数为扩容阈值和负载因子
     */
    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);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

    /**
     * 初始化方法传入参数为扩容阈值 
     */
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);//负载因子默认为DEFAULT_LOAD_FACTOR
    }

    /**
     * 空参构造函数  负载因子默认为DEFAULT_LOAD_FACTOR
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
    }

    /**
     * 传入Map进行构造  负载因子默认为DEFAULT_LOAD_FACTOR
     */
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }
    /**
     * 根据Map初始化一个HashMap
     */
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();	//获取map大小
        if (s > 0) {		//传入map非空
            if (table == null) { // 数组为空
                float ft = ((float)s / loadFactor) + 1.0F;	//获取当前table容量
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);		//最大值校验
                if (t > threshold)	//若得到值大于默认值
                    threshold = tableSizeFor(t);	//重新计算HashMap的扩容阈值
            }
            else if (s > threshold)		//数组非空  判断当前是否需要扩容
                resize();	//扩容(之后再说)
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {	//遍历节点
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);	//将值存入HashMap中(之后再说)
            }
        }
    }

    /**
     * 对cap进行转换   转换成大于等于cap的最小的2的整数次幂的数
     */
    static final int tableSizeFor(int cap) {
        int n = cap - 1;	//当前值-1避免传入值为2的整数次幂时计算值出错
        //当前值二进制为  ***1***
        n |= n >>> 1;	//处理后	***11***	
        n |= n >>> 2;	//处理后***1111**
        n |= n >>> 4;	//同上
        n |= n >>> 8;	//同上
        n |= n >>> 16;	//处理n值为 大于等于cap的最小的2的整数次幂的数 - 1
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

本文连接,转载请标注https://blog.csdn.net/luo_mu_hpu/article/details/106191080

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值