HashMap 源码分析 1.8

面试必备:HashMap(JDK1.8)原理以及源码分析 对于HashMap想必大家都不陌生,无论是平时code还是面试都经常和它打交道。今天我们通过源码的层面来分析一下它的实现原理,注意本文基于的是JDK1.8。 问题是从哪边开始聊起呢?我觉得不妨先从一段熟悉的代码开始。 Map<Integer, String> map = new HashMap<Integer, String>();map.put(1, "Jack"); 然后我们会迫不及待点开HashMap这个类,发现里面有大量的属性和方法,一脸懵逼。那就直接点开put. 阅读详情

之前看过JDK1.7的hashMap的源码,1.8在HashMap上做了不少改动,特找了相关文章,分享一下: 

1.7版本的hashmap采用:数组+链表;

1.7版本的hashmap采用:数组+链表+红黑树;

 HashMap是Java和Android程序员的基本功, JDK1.8对HashMap进行了优化, 你真正理解它了吗? 

考虑如下问题:  

1、哈希基本原理?(答:散列表、hash碰撞、链表、红黑树)

2、hashmap查询的时间复杂度, 影响因素和原理? (答:最好O(1),最差O(n), 如果是红黑O(logn))
3、resize如何实现的, 记住已经没有rehash了!!!(答:拉链entry根据高位bit散列到当前位置i和size+i位置)

4、为什么获取下标时用按位与&,而不是取模%? (答:不只是&速度更快哦,  我觉得你能答上来便真正理解hashmap了)

5、什么时机执行resize?

答:hashmap实例里的元素个数大于threshold时执行resize(即桶数量扩容为2倍并散列原来的Entry)。 PS:threshold=桶数量*负载因子


final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;   //初始化桶,默认16个元素
    if ((p = tab[i = (n - 1) & hash]) == null)   //如果第i个桶为空,创建Node实例
        tab[i] = newNode(hash, key, value, null);
    else { //哈希碰撞的情况, 即(n-1)&hash相等
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;   //key相同,后面会覆盖value
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);  //红黑树添加当前node
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);  //链表添加当前元素
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);  //当链表个数大于等于7时,将链表改造为红黑树
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;            //覆盖key相同的value并return, 即不会执行++size
        }
    }
    ++modCount;
    if (++size > threshold)    //key不相同时,每次插入一条数据自增1. 当size大于threshold时resize
        resize();
    afterNodeInsertion(evict);
    return null;
}

6、为什么负载因子默认为0.75f ? 能不能变为0.1、0.9、2、3等等呢?

答:0.75是平衡了时间和空间等因素; 负载因子越小桶的数量越多,读写的时间复杂度越低(极限情况O(1), 哈希碰撞的可能性越小); 负载因子越大桶的数量越少,读写的时间复杂度越高(极限情况O(n), 哈希碰撞可能性越高)。 0.1,0.9,2,3等都是合法值。

7、影响HashMap性能的因素?

1、 负载因子;

2、哈希值;理想情况是均匀的散列到各个桶。 一般HashMap使用String类型作为key,而String类重写了hashCode函数。


   static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
8、HashMap的key需要满足什么条件? 

答:必须重写hashCode和equals方法, 常用的String类实现了这两个方法。

示例代码:

    private static class KeyClass {
        int age;
        String name;
 
        public boolean equals(Object anyObject) {
            if (anyObject == this) {
                return true;
            }
 
            if (anyObject instanceof KeyClass) {
                KeyClass obj = (KeyClass) anyObject;
                if (obj.age == this.age
                        && obj.name == this.name) {
                    return true;
                }
            }
            return false;
        }
 
        public int hashCode() {
            return name==null? age : age|name.hashCode();
        }
    }
 
    public static void main(String[] args) {
        HashMap<KeyClass, String> map = new HashMap<>();
        KeyClass obj1 = new KeyClass();
        KeyClass obj2 = new KeyClass();
        obj1.age = 1;
        obj1.name = "Tom";
        obj2.age = 2;
        obj2.name ="Jack";
        map.put(obj1, "aaa");
        map.put(obj2, "bbb");
        map.put(obj1, "ccc");
        map.put(obj2, "ddd");
 
        map.forEach((key, value) -> {
            System.out.println(key.name + "---" + value);
        });
    }
输出:
Tom---ccc
Jack---ddd
9、HashMap允许key/value为null, 但最多只有一个。 为什么?  

答: 如果key为null会放在第一个桶(即下标0)位置, 而且是在链表最前面(即第一个位置)。 

JDK1.8的HashMap源码: http://www.grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/HashMap.java#HashMap

        我的习惯是先看注释再看源码并调试, 先翻译一下源码注释吧, 不准之处请指正哈。

Hash table based implementation of the Map interface. This implementation provides all of the optional map

   HashTable实现了Map接口类, 这些接口实现了所有可选的map功能, 包括允许空值和空key。

operations, and permits null values and thenull key. (TheHashMap class is roughly equivalent toHashtable, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

       HashMap和HashTable基本一致,  区别是HashMap是线程不同步的且允许空key。 HashMap不保证map的顺序, 而且顺序是可变的。

This implementation provides constant-time performance for the basic operations (get andput), assuming the hash function disperses the elements properly among the buckets.

    如果将数据适当的分散到桶里, HashMap的添加、查询函数的执行周期是常量值。

Iteration over collection views requires time proportional to the "capacity" of theHashMap instance (the number of buckets) plus its size (the number of key-value mappings). Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.

    使用迭代器遍历所有数据的性能跟HashMap的桶(bucket)数量有直接关系,   为了提高遍历的性能, 不能设置比较大的桶数量或者负载因子过低。

An instance of HashMap has two parameters that affect its performance:initial capacity andload factor. Thecapacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created.

      HashMap实例有2个重要参数影响它的性能: 初始容量和负载因子。 初始容量是指在哈希表里的桶总数, 一般在创建HashMap实例时设置初始容量。

The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased.

       负载因子是指哈希表在多满时扩容的百分比比例。

When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table isrehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.

       当哈希表的数据个数超过负载因子和当前容量的乘积时, 哈希表要再做一次哈希(重建内部数据结构), 哈希表每次扩容为原来的2倍。

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of theHashMap class, including get and put). 

        负载因子的默认值是0.75, 它平衡了时间和空间复杂度。 负载因子越大会降低空间使用率,但提高了查询性能(表现在哈希表的大多数操作是读取和查询)

The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur.

       考虑哈希表的性能问题, 要设置合适的初始容量,   从而减少rehash的次数。 当哈希表中entry的总数少于负载因子和初始容量乘积时, 就不会发生rehash动作。

If many mappings are to be stored in a HashMap instance, creating it with a sufficiently large capacity will allow the mappings to be stored more efficiently than letting it perform automatic rehashing as needed to grow the table. Note that using many keys with the same hashCode() is a sure way to slow down performance of any hash table. To ameliorate impact, when keys arejava.lang.Comparable, this class may use comparison order among keys to help break ties. 

      如果有很多值要存储到HashMap实例中, 在创建HashMap实例时要设置足够大的初始容量, 避免自动扩容时rehash。 如果很多关键字的哈希值相同, 会降低哈希表的性能。 为了降低这个影响, 当关键字支持java.lang.Comparable时, 可以对关键字做次排序以降低影响。

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at

least one of the threads modifies the map structurally, itmust be synchronized externally. (A structural modification

   哈希表是非线程安全的, 如果多线程同时访问哈希表, 且至少一个线程修改了哈希表的结构, 那么必须在访问hashmap前设置同步锁。(修改结构是指添加或者删除一个或多个entry, 修改键值不算是修改结构。)

is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. 

     一般在多线程操作哈希表时,  要使用同步对象封装map。

If no such object exists, the map should be "wrapped" using theCollections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

      如果不封装Hashmap, 可以使用Collections.synchronizedMap  方法调用HashMap实例。  在创建HashMap实例时避免其他线程操作该实例, 即保证了线程安全。

   Map m = Collections.synchronizedMap(new HashMap(...));

       JDK1.8对哈希碰撞后的拉链算法进行了优化, 当拉链上entry数量太多(超过8个)时,将链表重构为红黑树。  下面是源码相关的注释:

   * This map usually acts as a binned (bucketed) hash table, but
      * when bins get too large, they are transformed into bins of
      * TreeNodes, each structured similarly to those in
      * java.util.TreeMap. Most methods try to use normal bins, but
      * relay to TreeNode methods when applicable (simply by checking
      * instanceof a node).  Bins of TreeNodes may be traversed and
      * used like any others, but additionally support faster lookup
      * when overpopulated. However, since the vast majority of bins in
      * normal use are not overpopulated, checking for existence of
      * tree bins may be delayed in the course of table methods.

看看HashMap的几个重要成员变量:

 //The default initial capacity - MUST be a power of two.

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //为毛不写成16??? 大师是想用这种写法告诉你只能是2的幂

 HashMap的初始容量是16个, 而且容量只能是2的幂。  每次扩容时都是变成原来的2倍。

static final float DEFAULT_LOAD_FACTOR = 0.75f;

默认的负载因子是0.75f, 16*0.75=12。即默认的HashMap实例在插入第13个数据时,会扩容为32。

The bin count threshold for using a tree rather than list for a bin. Bins are converted to trees when adding an element to a bin with at least this many nodes. The value must be greater than 2 and should be at least 8 to mesh with assumptions in tree removal about conversion back to plain bins upon shrinkage.
static final int TREEIFY_THRESHOLD = 8;

注意:这是JDK1.8对HashMap的优化, 哈希碰撞后的链表上达到8个节点时要将链表重构为红黑树,  查询的时间复杂度变为O(logN)。

The table, initialized on first use, and resized as necessary. When allocated, length is always a power of two. (We also tolerate length zero in some operations to allow bootstrapping mechanics that are currently not needed.) 
transient Node<K,V>[] table;  //HashMap的桶, 如果没有哈希碰撞, HashMap就是个数组,我说的是如果。  数组的查询时间复杂度是O(1),所以HashMap理想时间复杂度是O(1);如果所有数据都在同一个下标位置, 即N个数据组成链表,时间复杂度为O(n), 所以HashMap的最差时间复杂度为O(n)。如果链表达到8个元素时重构为红黑树,而红黑树的查询时间复杂度为O(logN), 所以这时HashMap的时间复杂度为O(logN)。

Holds cached entrySet(). Note that AbstractMap fields are used for keySet() and values().
transient Set<Map.Entry<K,V>> entrySet; //HashMap所有的值,因为用了Set, 所以HashMap不会有key、value都相同的数据。

                               

                                                       哈希表的结构

1、 哈希碰撞的原因和解决方法:

     哈希碰撞是不同的key值找到相同的下标,  对应HashMap里hashcode和容量的模相同。

源码629行    if ((p = tab[i = (n - 1) & hash]) == null) , 其中n是容量值,    即用哈希值和容量相与得到要保存的位置。 如果不同Key的(n - 1) & hash相同, 那么要存储到同一个数组下标位置, 这个现象就叫哈希碰撞。

        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {

          ....

         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;      //如果哈希值相同而且key相同, 则更新键值
             else if (p instanceof TreeNode)
                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);  //如果下标数据是TreeNode类型,则将新数据添加到红黑树中。
             else {
                 for (int binCount = 0; ; ++binCount) {
                     if ((e = p.next) == null) {
                         p.next = newNode(hash, key, value, null);   //将新Node添加到链表末尾
                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                             treeifyBin(tab, hash);    //如果链表个数达到8个时,将链表修改为红黑树结构
                         break;
                     }     

            .....

           }

2、JDK1.8对HashMap最大的优化是resize函数,  在扩容时不再需要rehash了, 下面就看看大师是怎么实现的。

Initializes or doubles table size. If null, allocates in accord with initial capacity target held in field threshold. Otherwise, because we are using power-of-two expansion, the elements from each bin must either stay at same index, or move with a power of two offset in the new table.

初始化数组或者扩容为2倍,   初值为空时,则根据初始容量开辟空间来创建数组。否则, 因为我们使用2的幂定义数组大小,数据要么待在原来的下标, 或者移动到新数组的高位下标。 (举例: 初始数组是16个,假如有2个数据存储在下标为1的位置, 扩容后这2个数据可以存在下标为1或者16+1的位置)

Returns:
    the table
final Node<K,V>[] resize() {

         ....

         newThr = oldThr << 1; // double threshold,   大小扩大为2倍,出于性能考虑和者告诉使用者它是2的幂, 这里用的是位移, 而不是*2,

   if (e.next == null)
      newTab[e.hash & (newCap - 1)] = e;  //如果该下标只有一个数据,则散列到当前位置或者高位对应位置(以第一次resize为例,原来在第4个位置,resize后会存储到第4个或者第4+16个位置)
  else if (e instanceof TreeNode)
     ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);  //红黑树重构

   else {

     do {
        next = e.next;
        if ((e.hash & oldCap) == 0) {    
            if (loTail == null)
               loHead = e;
            else
            loTail.next = e;
            loTail = e;
        } else {
            if (hiTail == null)
               hiHead = e;
            else
               hiTail.next = e;
               hiTail = e;
         }
      } while ((e = next) != null);
      if (loTail != null) {
          loTail.next = null;
          newTab[j] = loHead;   //下标不变
      }
      if (hiTail != null) {
          hiTail.next = null;
          newTab[j + oldCap] = hiHead; //下标位置移动原来容量大小
      }

   (e.hash & oldCap) == 0写的很赞!!! 它将原来的链表数据散列到2个下标位置,  概率是当前位置50%,高位位置50%。     你可能有点懵比, 下面举例说明。  上边图中第0个下标有496和896,  假设它俩的hashcode(int型,占4个字节)是

resize前:

496的hashcode: 00000000  00000000  00000000  00000000

896的hashcode: 01010000  01100000  10000000  00100000

oldCap是16:       00000000  00000000  00000000  00010000

    496和896对应的e.hash & oldCap的值为0, 即下标都是第0个。

resize后:


496的hashcode: 00000000  00000000  00000000  00000000

896的hashcode: 01010000  01100000  10000000  00100000

oldCap是32:       00000000  00000000  00000000  00100000
   496和896对应的e.hash & oldCap的值为0和1, 即下标都是第0个和第16个。

   看明白了吗?   因为hashcode的第n位是0/1的概率相同, 理论上链表的数据会均匀分布到当前下标或高位数组对应下标。

       回顾JDK1.7的HashMap,在扩容时会rehash即每个entry的位置都要再计算一遍,  性能不好呀, 所以JDK1.8做了这个优化。

      再回到文章最开始的问题, HashMap为什么用&得到下标,而不是%?   如果使用了取模%, 那么在容量变为2倍时, 需要rehash确定每个链表元素的位置。

     很佩服HashMap的作者呀,  大师在运算符的使用上都是这么考究!!!

PS: 顺便说一下ArrayList, 初始容量是10个, 每次扩容是原来的1.5倍。

相关1.7版本的分析:

https://www.cnblogs.com/chengxiao/p/6059914.html
--------------------- 
原文:https://blog.youkuaiyun.com/brycegao321/article/details/52527236 

静态与动态LACP链路聚合:原理、配置与排错实战指南 链路聚合技术是提升网络带宽与可靠性的核心方案,通过将多个物理端口逻辑捆绑,实现带宽叠加与链路冗余。其原理基于IEEE 802.3ad标准,通过负载均衡算法将数据流分布到不同物理链路,既避免了数据包乱序,又提升了整体吞吐量。该技术的核心价值在于消除单端口瓶颈、提供毫秒级故障切换,并能简化网络拓扑管理。在企业服务器接入、数据中心互联及虚拟化平台等场景中,链路聚合已成为构建高可用网络的基础。实践中,动态LACP模式通过协议报文协商,能主动检测链路故障并防止配置错误导致的网络环路,相比静态聚合更为可靠。本文将深入解 阅读详情

相关推荐

某教育平台线上用户流失分析

本项目基于某教育平台的用户登录信息、用户个人信息以及用户课程学习记录三信息表,挖掘了平台流量以及用户流失等信息。使用python对数据进行预处理,使用tableau进行数据可视化分析。该教育平台正值窗口期,平台流量没有良好的留存水平,但有良好的发展趋势,需要深入分析用户留存率低,做好招新促活营销。该教育平台的基本盘在广东、湖北、河南、贵州等省份,线上教育的潜在用户可能更多分布在线下教育资源不充足、受疫情影响更为严重的地区。

fhy12的博客 1300

Java-HashMap-forEach源码分析

Java HashMap EntrySet 内部类 的 forEach 方法 分析 其实是我写错了,本来应该 分析 HashMap 的结果源码找错了位置强行 分析了 这里的 // forEach 遍历HashMap的元素 // final 代表不可修改 在这个方法也没有返回值 // 传进来的参数有 Consumer<? super Map.Entry<K,V>> 是一个 action public final void

韩旭051的博客 934

第二十三章 Nest集成日志框架Winston

Winston是一个非常流行的Node.js日志框架,而Nest.js是一个基于Node.js的后端框架。修改 winston.module.ts 内容如下 添加 forRoot 方法,接收 winston 的 createLogger 方法的参数,返回动态模块的 providers、exports。这里用到了 printf 的 format 函数,它可以自定义打印的日志格式 且使用了chalk 加上了颜色,并且打印了 dayjs 格式化的时间。可以看到控制台打印了自定义的 logger 的自定义。

枫ゞ的博客 1071

HashMap1.8源码

HashMap1.8源码

weixin_44339533的博客 362

麒麟信安3.3-6C电网版虚拟机安装避坑指南:从ISO下载到SSH配置全流程

本文提供麒麟信安3.3-6C电网版虚拟机的详细安装与配置指南。针对电力行业仿真测试需求,重点解析从ISO镜像获取、虚拟机环境准备、安装过程中的三大“雷区”(如多管理员密码逻辑、分区方案、网络配置)到首次启动后的网络、SSH及root策略配置的全流程避坑要点,帮助技术人员高效、安全地完成部署。

rainy的博客 855

Seedance2.5本地部署:从环境配置到批量生图的工程实践指南

最近在几个技术社群里,看到不少人在讨论 AI 生图和视频工具。有人抱怨在线服务要么贵、要么慢、要么生成内容受限;也有人尝试了各种“免费”方案,结果不是功能残缺就是暗藏收费陷阱。就在大家觉得“又好又免费”的本地部署方案门槛太高时,Seedance2.5 突然冒了出来,而且口号相当直接:本地部署、完全免费、不联网、功能对标甚至超越一些付费产品。 但这类宣传我们见多了,真正的问题是:它到底能不能在普通开发者的机器上跑起来?生成质量是否真的可用?长期使用会不会遇到模型崩溃、依赖冲突或者资源爆炸?更重要的是,对于一个

weixin_27419879的博客 1140

Java重点源码回顾——HashMap1.8

在之前的文章中,我们介绍了HashMap1.7的源码,今天我们来看下HashMap1.8的源码。HashMap1.8相比于1.7最大的改变就是改变了1.7中采用数组+链表的方式存储键值对,转而由数组+链表+红黑树的方式来存储键值对。HashMap1.8的底层结构如下图所示:当链表中结点数较少(小于8)的时候,还是采用数组+链表的方式。当链表中结点过多,就会造成查找效率低下的情况,就会转而采用数组+红黑树的方式。

热爱永不过时! 1213

安卓集成华为HMS Scankit实现自定义扫码功能

实现扫码功能 使用的是集成华为扫描的SDK,UI界面借鉴的是谷歌官方的Zxing项目中的自定义view,两者结合实现。 先上效果图: 先在项目根级别(build.gradle)当中配置HMS Core SDK的Maven仓地址。 // 配置HMS Core SDK的Maven仓地址。 maven {url 'https://developer.huawei.com/repo/'} // 配置HMS Core SDK的Maven仓地址。 maven {url 'https://developer.huaw

qq_47625961的博客 5514

面试官:JDK1.8 HashMap扩容rehash算法是如何优化的?

本文跟大家聊一聊一个常见的面试题,那就是JDK1.8 HashMap扩容rehash算法是如何优化的? 众所周知HashMap的底层其实是一个数组,既然是一个数组,必然长度是固定的,也就一定存在扩容的问题。在JDK1.7的时候,是将数组扩容为两倍,然后将HashMap中所有的key重新进行hash寻址算法然后再放入到扩容后的新的数组的新的位置。 但是从JDK1.8之后,对rehash进行了优化,减少了对key重新进行hash寻址算法的过程,具体怎么实现的,这就上源码。 我们都知道HashMap扩容是通

weixin_45630885的博客 3914

YOLOv13添加DRB模块map暴涨12.33!准确率提升8.56!召回率提升15.66

本文介绍了在YOLOv13模型中添加DRB模块的改进方法。实验结果显示,添加DRB模块后模型性能显著提升,mAP暴涨12.33%,准确率提升8.56%。文章详细说明了移植过程,包括创建yolov13-DRB.yaml配置文件、修改tasks.py和__init__.py文件,以及引入UniRepLKNet模块的具体实现。其中重点描述了GRNwithNHWC、NCHWtoNHWC等核心组件的实现细节,并提供了完整的模型结构配置代码。这些改进使得YOLOv13模型在保持原有架构优势的同时,获得了更强大的特征提取

FJN110的博客 2822

基于FPGA的万兆以太网学习(1)

万兆(10G) 以太网测速视频:SFP+屏蔽笼可以插入千兆或万兆光模块。SFP+信号定义与 SFP 一致。

baidu_34971492的博客 2250

Java集合类:HashMap (基于JDK1.8)

文章目录前言HashMap的数据结构深入源码两个参数成员变量四个构造方法插入数据的方法:put()哈希函数:hash()动态扩容:resize()节点树化、红黑树的拆分节点树化红黑树拆分总结心得 前言 今天我们来学习Java中较为常用的集合类 HashMap。 另外说明一下,本文的 HashMap 源码是基于Jdk1.8版本的,如果没有特别说明的话,之后的集合类源码解析都是1.8的版本。 Hash...

7838

【BIM入门实战】Revit创建地形的几种方法及优缺点

Revit在体量和场地选项卡的【地形表面】工具可以创建三维地形,有三种方法:放置点、指定点文件和导入实例文件、倾斜摄影点云技术和InfraWorks地形生成。 文章目录1. 放置点2. 指定点文件3. 导入实例文件4. 倾斜摄影点云技术5. InfraWorks地形生成 1. 放置点 放置点功能位于体量和场地选项卡下地形表面,点开找到放置点,并通过自定义设置点的高程值来创建地形的高程数据。 优点:通过用户自定义高程点来绘制模型,使地形更为精确。 缺点:只适用于面积小的项目,面积太大,人工效率低下。 .

智慧空间实验室 4762

JDK1.8 HashMap原理及源码分析

概述 JDK1.8对HashMap底层的实现进行了优化,引入红黑树的数据结构和扩容的优化等。   HashMap源码分析 HashMap的put方法执行过程: putVal()源码分析: final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node&lt;K, V&gt;...

工作记录 802

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

HashMap源码分析(JDK1.8)

本文转自:https://www.cnblogs.com/xiaoxi/p/7233201.html,本来准备自己写的,但是自己理解的不够透彻,后来通过百度找到了这篇文章,原作者可以说写的很用心,分析的很到位,看完之后让我受益匪浅。 一、HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里。但是当位于一...

keyto1的博客 174

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

java HashMap源码分析(JDK1.8)

HashMap继承AbstractMap<K,V> ,implements Map<K,V>, Cloneable, Serializable 键值对存储,HashMap最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null. 源码中可以看到一个静态的内部类(单向链表):static class Node<K,V> imp...

来杯Java 1574

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

JDk1.8HashMap的源码分析

JDk1.8HashMap的源码分析 HashMap用数组存放数据(总结) 调用键的hashCode()获得键的哈希值 用哈希值,计算一个下标值 i 新建Entry对象来封装键和值 Entry对象放在 i 位置 空位置,直接放入 有数据,依次用equals()比较是否相等 找到相等的,覆盖值 没有相等的,链表连接在一起 负载率、加载因子到0.75 新建翻倍容量的新数组 所有数据,重新哈希,放...

smileLs的博客 147

JDK1.8HashMap源码分析

JDK1.8 HashMap源码分析

a2231476020的博客 184

HashMap源码分析1.8

HashMap1.8的升级主要是修复1.8的问题: 目录 1.重要源码分析 2.结构组成? 3.如何解决在扩容的时候碰到的链表死循环的问题 4.如何解决时间复杂度从O(0)-->O(n)的过程 1.重要源码分析 /* * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to li

Mr_xiayijie的博客 317

hashmap源码分析、扩容过程,1.7与1.8的区别

Java:手把手带你源码分析 HashMap 1.7https://blog.csdn.net/carson_ho/article/details/79373026 Java源码分析:关于 HashMap 1.8 的重大更新https://blog.csdn.net/carson_ho/article/details/79373134 ...

【小石头的茅坑】 71万+

HashMap 1.8版本的原理介绍以及源码分析 1.7与1.8版本的区别及改进

HashMap原理介绍 HashMap 的结构是 数组 + 链表 + 红黑树; 首先HashMap在初始化时并不会申请连续的存储空间,而是在存数据(put)时申请,这样做是为了避免内存空间的浪费。 在初始化后,我们第一次向数组中put键值对时,需要让key值经过一个扰动函数(哈希函数),目的是为了让key值更加散列化,在极大程度上避免重复。key值经过扰动后将得到32位的固定长度的二进制值;将这...

quique的博客 457

JDK源码分析——HashMap(JDK1.8)

1. 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap。HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现。HashMap 允许 null 键和 null 值,在计算哈键的哈希值时,null 键哈希值为 0。HashMap 并不保证键值对的顺序,这意味着在进行某些操作后,键值对的顺序可能会发生变化。另外,需要注意的是,HashMap 是非线程安全类,在多...

小马不奔腾的博客 417

HashMap工作原理回顾 (基于JDK1.8源码分析)

HashMap工作原理回顾 (基于JDK1.8源码分析) 空的HashMap()构造方法 /** * 默认初始容量为16. */ static final int DEFAULT_INITIAL_CAPACITY = 1 &amp;amp;lt;&amp;amp;lt; 4; // aka 16 /** * 最大容量为2的30次方,如果有参构造器指定了更大的数值,那么仍...

wendrewshay 793

7.Java SDK源码分析系列笔记-JDK1.8 HashMap

1.1.Java SDK源码分析系列笔记-Integer2.2.Java SDK源码分析系列笔记-String系列3.3.Java SDK源码分析系列笔记-LinkedList4.4.Java SDK源码分析系列笔记-ArrayList5.5.Java SDK源码分析系列笔记-Vector6.6.Java SDK源码分析系列笔记-SynchronizedList7.7.Java SDK源码分析系列笔记-JDK1.8 HashMap8.

weixin_40316402的博客 94

Java集合之HashMap(1.7和1.8)源码分析

Java集合之HashMap 本文将从以下几个方面来理解HashMap: 什么是哈希表 HashMap源码分析 HashMap和HashTable的区别 1.7和1.8有什么区别 哈希表 哈希表是种数据结构,它可以提供快速的插入操作和查找操作。第一次接触哈希表时。不论哈希表中有多少数据,插入和删除(有时包括侧除)只需要接近常量的时间即0(1)的时间级。 为什么哈希这么快呢 首先不得不提哈希函数了( p= H(key) ),哈希函数就是给一个任意大小的数据生成出一个固定长度的数据,作为它的映射 ,这种

全是bug写个蛇的博客 334

Java源码分析:HashMap 1.8 相对于1.7区别

https://juejin.im/post/5aa5d8d26fb9a028d2079264

u014253011的博客 247
上一篇: Linux企业运维人员最常用150个命令汇总
下一篇: HsahMap 之红黑介绍
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值