JDK源码学习~HashMap(一)

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

类定义:

HashMap继承了AbstractMap,实现Map,Cloneable,Serializable 接口

AbstractMap:  实现了一些方法,这里不做解释;

Cloneable:是一个标识接口,(应该是表示实现它的类允许被复制之类的。。。。)

 

构造方法:

/**
    initialCapacity : MAP的初始容量
    loadFactor :加载因子/系数
*/
public HashMap(int initialCapacity, float loadFactor) {
        //初始容量不能设置为小于0
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);

        // MAXIMUM_CAPACITY是最大容量,默认是1 << 30 = 1073741824
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        //加载因子必须大于0
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        //获取下一次达到需要调整扩容的大小(容量*加载因子)
        this.threshold = tableSizeFor(initialCapacity);
    }


/**
    设置初始容量
    使用默认加载因子初始化Map,默认为0.75
*/
public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

/**
    使用默认容量和加载因子初始化Map
*/
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

/**
    将Map作为模板参数直接导入本HashMap
*/
public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

 

类成员:

//默认的初始容量大小 16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

//HashMap的最大容量 1073741824
static final int MAXIMUM_CAPACITY = 1 << 30;

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

//使用红黑树替代链表的阈值,>= 这个阈值链表将转化为红黑树
static final int TREEIFY_THRESHOLD = 8;

//当同一个桶上链表节点<= 6时,红黑树将转化为链表,反转
static final int UNTREEIFY_THRESHOLD = 6;

//HashMap可以将链表转化为树结构的最小阈值,也就是要达到64个桶位,才会开启转化
 static final int MIN_TREEIFY_CAPACITY = 64;

//存储键值对数据
 transient Set<Map.Entry<K,V>> entrySet;

//本HashMap中键值对数量
transient int size;

//此HashMap中结构变化的次数,改动次数
transient int modCount;

//如果初始化没有给HashMap分配桶容量大小,则这里保存的是默认大小DEFAULT_INITIAL_CAPACITY值
int threshold;

//这个存储的也是加载因子,而DEFAULT_LOAD_FACTOR 是没有指定情况下默认的加载因子
final float loadFactor;

下面看下HashMap的数据结构

transient Node<K,V>[] table;


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

可以看出,HashMap基本结构是由数组+链表形式,如上图 array [1]  所示

    数组中每个元素都是Node<K,V>类型,也就是键值对形式

static class Node<K,V> implements Map.Entry<K,V> {

        final int hash;  //哈希值
        final K key;  //key值
        V value;  //Value值
        Node<K,V> next;  //下一个节点对象的引用/指针
}

也就是说,Node<K,V>数组每个元素都可以容纳一条链表,该元素就是它容纳的链表的头节点,通过访问它的next属性,就可以遍历该链表所有元素。

主要看下节点类的3个方法

        /**
            获取该节点的Hash值
            key的hash 和 value的hash  用按位异或运算
        */
        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        /**
            给该节点设置新值,返回原来的值
        */
        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        /**
            比较node节点对象内容是否相同
        */
        public final boolean equals(Object o) {
            //如果对象引用指向同一个对象,则相同
            if (o == this)
                return true;
          
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                将key和value值进行比较,2者相同则相同
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值