Map接口的实现类---HashMap

HashMap

类定义

public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable
        
        注意:Map接口的定义
               public interface Map<K, V> 没有父接口

具体的内部数据存储方式

transient Node<K,V>[] table; //哈希表的本质是一个数组,数组中每一个元素称为一个桶,桶中存放的是键值对
 

transient Set<Map.Entry<K,V>> entrySet;并不是用于实际存储数据,主要用于针对entrySet和keySet两个视图提供支持

transient int size;当前集合中的元素个数
 
final float loadFactor;  当前集合的负载因子,当前Map集合中扩容的阈值【负载因子*最大容积】

transient int modCount;修改次数,主要用于实现多线程操作时的快死异常

重要的阈值

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 默认的初始化容积

static final int MAXIMUM_CAPACITY = 1 << 30;最大容积值,实际上就是2的30次方

static final float DEFAULT_LOAD_FACTOR = 0.75f; 默认的负载因子/加载因子

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

static final int MIN_TREEIFY_CAPACITY = 64;//最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即将链表转换成红黑树)否则,若桶内元素太多时,则直接扩容,而不是树形化

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

内部存储的实现

静态内部类用于实现Entry,HahMap中存放的key/value对就被封装为Node对象。其中key就是存放的键值,用于决定具体的存放位置;value是具体存放的数据,hash就是当前Node对象的hash值,next用于指向下一个Node节点(单向链表) 
 
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;   下一个节点对象   --- 默认使用单向链表结构,当一个链表上的节点数>8并且总存储元素个数>64时自动转换为红黑树

构造器

public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; //给属性loadFactor负载因子赋默认值0.75
        //并没有对数组进行初始化操作。采用延迟初始化的策略可以节约空间
    }
    
    //当指定初始化容积时,调用另外的构造器进行HashMap的初始化,采用默认的负载因子0.75
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    
    //2个参数的构造器,参数1初始化容积大小,参数2负载因子
    public HashMap(int initialCapacity, float loadFactor) {
        //对初始化容积值进行合法性验证,如果<0则抛出异常
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
            
        if (loadFactor <= 0 || Float.isNaN(loadFactor))  负载因子应该在(0,1]之间的浮点数
            //负载因子越小,哈希碰撞的概率越低,也就意味着链表长度越小,但是浪费空间;如果值越大,则节约空间,但是哈希碰撞概率提高,所以一般建议值在(0,1]之间
            throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
            
        this.loadFactor = loadFactor;   //接收合法的负载因子值
        this.threshold = tableSizeFor(initialCapacity);    并不是直接使用传入的参数作为初始化数组的长度,而是将传入的整数转换大于等于initialCapacity的最小2的n次方值
            例如initialCapacity=5,则真正的初始化容积为8
            initialCapacity=10,则真正的初始化容积为16
        
    }
    
    Float.isNaN判断参数是否为一个不是数值  NaN含义为Not a number
     public static boolean isNaN(float v) {
        return (v != v);
    }
    
    //根据传入的初始化容积值求一个合法的初始化容积值
     static final int tableSizeFor(int cap) {
        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值