HashMap源码分析一(jdk8)

本文深入分析了JDK8中HashMap的结构和实现,包括数组+链表+红黑树的设计原因,成员变量,构造方法,以及put、get、size等关键方法的实现。特别讨论了扩容机制和链表转红黑树的条件,同时指出HashMap非线程安全,建议在需要时使用Collections.synchronizedMap()。
摘要由CSDN通过智能技术生成

一、概述

在这里插入图片描述
jdk8中hashmap的结构如图所示,它是由数组+链表+红黑树组成,jdk8之前是由数组+链表组成,那么为什么要这么做那?让我们带着疑问一步步往下看。首先看下这几个基本组成结构:

  • 数组:数组存储结构是连续的,空间复杂度大,但查询的时间复杂度小。其寻址(通过下标搜索)效率高,一般的插入和删除效率低。
  • 链表:链表存储结构是离散的,空间复杂度小。其寻址(通过下标搜索)效率低,一般的插入和删除效率高。
  • 红黑树:作为一种二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。由于链表的查询时间复杂度为O(n),所以当链表很长时转换成红黑树将很好的提高效率!

二、源码分析

1、成员变量

   //初始容量,默认为16,必须为2的指数倍
   static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 

   //最大容量,必须为2的指数倍
   static final int MAXIMUM_CAPACITY = 1 << 30;

    //默认负载因数
   static final float DEFAULT_LOAD_FACTOR = 0.75f;
   
    //树化阈值,当桶中链表的长度大于8时将其转换为红黑树
   static final int TREEIFY_THRESHOLD = 8;
  
   //链表化阈值,当resize或删除操作时,桶中的元素数低于该值,将把红黑树转换成链表
   static final int UNTREEIFY_THRESHOLD = 6;

    //容器可以被树形化的最小容量,应该至少是4 * TREEIFY_THRESHOLD以避免调整大小和树状化阈值之间的冲突
    static final int MIN_TREEIFY_CAPACITY = 64;

   //存储元素的数组,第一次使用时初始化
   transient Node<K,V>[] table;

   //缓存entrySet
   transient Set<Map.Entry<K,V>> entrySet;

   //map的大小即map中包含的键值对的大小
   transient int size;

   //map被结构修改的次数,map被迭代时采用fail-fast机制
  transient int modCount;

   //扩容阈值,threshold = capacity * load factor
   int threshold;

  //当前负载因数,用来衡量hashmap空间占比情况,计算方法是size/capacity
  final float loadFactor;

链表的结构代码 :

//为单向链表
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;
    }

//两个节点只有键和值都相等时才返回true
    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;
    }
}

红黑树结构代码,红黑树的讲解可以参考该博客红黑树详解

    /**
     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
     * extends Node) so can be used as extension of either regular or
     * linked node.
     */
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值