javaSe——hashmap jdk1.8


hashjdk1.7的实现看另一篇

1.实现的接口

在这里插入图片描述
jdk1.8的hashmap 和 1.7的一样都是实现一个map接口
在这里插入图片描述
包含了一些操作kv键值的一些常用的方法,get(),put(),remove()等等。
在这里插入图片描述
依然使用一个Set集合来保存所有的key,保证key的唯一性

2.内部类

在这里插入图片描述
迭代器就不介绍了。相较于jdk1.7,这里的出现了两个内部类,node和treeNode。

  • Node
    在这里插入图片描述
    点进去,这不就是jdk1.7版本中的entry嘛,这里只是修改了一下名字而已。功能也是一样的,用来保存每个kv键值对,next用于哈希冲突时,链接下一个Node。

  • TreeNode(红黑树节点)
    在这里插入图片描述
    这就是jdk1.8中引入的红黑树。分析成员,

  • parent 父节点

  • left 左子节点

  • right 右子节点

  • red 判断是否时红黑树

  • pre 指向链表的前一个节点

这里比较令人好奇的是红黑树中为什么会需要pre节点?这个不是用于双向链表中吗?
进入继承类中
在这里插入图片描述
在进入
在这里插入图片描述
到这里就知道答案了,TreeNode 内部隐式的继承了Node节点,因为node是单链表,只有next,这里存在一个pre,在内部隐式的构成了以双向链表。 —— 关于有什么作用后面在分析。

3.hashmap内部的成员

transient Node<K,V>[] table;

    /**
     * Holds cached entrySet(). Note that AbstractMap fields are used
     * for keySet() and values().
     */ kv的set集合
    transient Set<Map.Entry<K,V>> entrySet;

    /**
     * The number of key-value mappings contained in this map.
     */
     哈希表中实际的键值对的数量
    transient int size;

    /**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     */
     哈希表的修改次数 —— 用于迭代器时,方式在迭代的过程中删除哈希表中的数据做判断
    transient int modCount;

    /**
     * The next size value at which to resize (capacity * load factor).
     *
     * @serial
     */
    // (The javadoc description is true upon serialization.
    // Additionally, if the table array has not been allocated, this
    // field holds the initial array capacity, or zero signifying
    // DEFAULT_INITIAL_CAPACITY.)
    阙值 —— 用于扩容的时的判断
    int threshold;

    /**
     * The load factor for the hash table.
     *
     * @serial
     */
     负载因子,用于计算阙值
    final float loadFactor;

分析可以知道,jdk8的成员和jdk7的基本是一致的。

4.默认值 (注意)

在这里插入图片描述
默认初始容量
最大容量
负载因子
上面的三个属性没有变化
在这里插入图片描述
但是在jdk8中多个3个默认的属性

  • TREEIFY_THRESHOLD = 8 表示树形的阙值
    就是哈希表中的某个槽位上的Node的数量大于8时,就会将其由链表变为红黑树

  • UNTREEIFY_THRESHOLD = 6
    取消树形化的阙值,红黑树种的节点的个数小于6时,就会将红黑树变为链表

  • MIN_TREEIFY_CAPACITY = 64
    树化时,哈希表的最小容量,因为树化完成之后,可能还会将红黑树转化为链表,转化过程种设计到槽位的重新计算,位置重新分配,保证哈希表种有足够的槽位

5.方法分析

5.1构造方法

在这里插入图片描述
可以看到依然是只有四个,所以这里就直接分析默认构造方法。
在这里插入图片描述
看到这里,忍不住笑了。jdkb做的比jdk7更绝,初始化时,就只是设置了一个默认的负载因子,jdk7好歹还设置了一下阙值,针对不同的实现,调用了一下init()方法。

然后看一下有参数的构造方法
在这里插入图片描述
参数值为初始化容量的大小,然后调用了另一个构成方法
在这里插入图片描述
这里就基本和jdk7一致,设置了一些基本的属性,包括阙值,负载因子,重点注意,这里依然没有对哈希表进行实例化(分配空间),真正的实例化过程在put()时才做。 好处就是,使用的懒加载机制,到正真使用哈希表时才初始化哈希表,提高空间利用率。

5.2put方法

在这里插入图片描述
不同于jdk1.7 直接在方法内部处理,这里是调用一个方法来处理put()。首先计算了一下hash值
在这里插入图片描述
计算的方式页没有1.7版本的复杂,直接调用了Object 对象的hashcod()函数得到哈希值
在这里插入图片描述
进入hashcode() 发现是一个native方法,所以可以知道计算hashcode值不是有java代码实现,而是c++ 实现。实现得原理是根据该对象在内存中得位置来计算得。 见下图
在这里插入图片描述
为什么不是用java 来实现,可能就是因为java操作内存比较慢,所以使用c++来实现。
计算得到得哈希值,然后向右逻辑循环右移了16位,使用高16位来作为哈希值,这种做法有个名字 —— 扰动函数

计算完哈希值,后进入方法体。 代码比较复杂,这里注释一些关键点

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
   
        Node<K,V>[] tab; Node<K,V> p; int n, i;
         首先判断哈希表是否位null,在前面构造函数中并没有初始化哈希表,这里需要初始化哈希表
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
   
            Node<K,V> e; K k;
            判断一
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
                判断二
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                判断三
            else {
   
                for (int 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值