【Java-集合】HashMap-Hash冲突解决

告别Nginx原始日志!VictoriaLogs+Grafana构建企业级应用日志分析平台实战 描述:做为一个合格的运维工程师,在面对企业安全运维管理中,日志审计是一项非常重要的工作。授人以鱼不如授人以渔,各位运友们可参照作者的方案设计,在自己的项目中根据实际情况调整落地,例如,不在仅仅采集 NGINX 应用日志,而是采集 Apache、Tomcat、SpringBoot 等多种应用服务器的日志,又如,不再仅仅采集网络设备、安全审计审计日志,而是 Windows、Linux 等多种操作系统的审计日志等,大家可充分发挥想象、实践能力,也欢迎大家在知识星球中分享自己的方案设计,一起交流学习。 阅读详情

【Java-集合】HashMap-Hash冲突解决

2017年10月22日 20:49:58 binke_mxb 阅读数:5371

 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/u012712901/article/details/78313130

背景:我们常用HashMap作为我们Java开发时的K-V数据存储结构(如id-person,这个ID对应这个人)。我们知道他们的数据结构么,它的Hash值是什么意义。Hash冲突是怎么解决的。我们带着这2个问题将HashMap做个整体剖析。(其实还有一个问题是,它怎么进行动态扩容的)

一、HashMap的数据结构是什么。

下面是HashMap中的源码。其实HashMap的本质是Node数组;K-V结构对应的基础数据结构就是以下源码

transient HashMap.Node<K, V>[] table;

static class Node<K,V> implements Map.Entry<K,V> {
        //Hash值
        final int hash;
        //Key值
        final K key;
        //Value值
        V value;
        //当前Node对应的下个Node(用于解决Hash冲突;稍后讲解)
        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 int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

根据上面代码我们知悉,HashMap中基本的数据结构是Node。

Map persons = new HashMap<String,String>();
//put方法会新建一个Node 
//hash=k.hashCode() ^ k >>> 16 ; hash是数组所在位置
//K="1",V="jack";next=null;(无Hash冲突情况)
persons.put("1","jack");
persons.put("2","john");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上述的Node数据结构中的hash值的意义是将Node均匀的放置在数组[]中。获得hash值后使用在table[(n - 1) & hash] 位置置值。

/**
* Computes key.hashCode() and spreads (XORs) higher bits of hash
* to lower.  Because the table uses power-of-two masking, sets of
* hashes that vary only in bits above the current mask will
* always collide. (Among known examples are sets of Float keys
* holding consecutive whole numbers in small tables.)  So we
* apply a transform that spreads the impact of higher bits
* downward. There is a tradeoff between speed, utility, and
* quality of bit-spreading. Because many common sets of hashes
* are already reasonably distributed (so don't benefit from
* spreading), and because we use trees to handle large sets of
* collisions in bins, we just XOR some shifted bits in the
* cheapest possible way to reduce systematic lossage, as well as
* to incorporate impact of the highest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
static final int hash(Object var0) {
    int var1;
    return var0 == null?0:(var1 = var0.hashCode()) ^ var1 >>> 16;
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

二、HashMap怎么处理hash冲突

上述说道,Node中的hash值是用hash算法得到的,目的是均匀放置,那如果put的过于频繁,会造成不同的key-value计算出了同一个hash,这个时候hash冲突了,那么这2个Node都放置到了数组的同一个位置。HashMap是怎么处理这个问题的呢?

解决方案:HashMap的数据结构是:数组Node[]与链表Node中有next Node.

HashMap中的实际数据结构

(1)如果上述的 persons.put(“1”,”jack”);persons.put(“2”,”john”); 同时计算到的hash值都为123,那么jack先放在第一列的第一个位置Node-jack,persons.put(“2”,”john”);执行时会将Node-jack的next(Node) = Node(john),Jack的下个节点将指向Node(john)。

(2)那么取的时候呢,persons.get(“2”),这个时候取得的hash值是123,即table[123],这时table[123]其实是Node-jack,Key值不相等,取Node-jack的next下个Node,即Node-John,这时Key值相等了,然后返回对应的person.

三、HashMap怎么进行动态扩容

JDK1.7的逻辑相对简单,JDK1.8使用了红黑树TreeMap相对复杂,现在用1.7的进行讲解。本质上其实一样。

void resize(int newCapacity) {   //传入新的容量  
    Entry[] oldTable = table;    //引用扩容前的Entry数组  
    int oldCapacity = oldTable.length;  
    if (oldCapacity == MAXIMUM_CAPACITY) {  //扩容前的数组大小如果已经达到最大(2^30)了  
        threshold = Integer.MAX_VALUE; //修改阈值为int的最大值(2^31-1),这样以后就不会扩容了  
        return;  
    }  

    Entry[] newTable = new Entry[newCapacity];  //初始化一个新的Entry数组  
    transfer(newTable);                         //!!将数据转移到新的Entry数组里  
    table = newTable;                           //HashMap的table属性引用新的Entry数组  
    threshold = (int) (newCapacity * loadFactor);//修改阈值  
}  

void transfer(Entry[] newTable) {  
    Entry[] src = table;                   //src引用了旧的Entry数组  
    int newCapacity = newTable.length;  
    for (int j = 0; j < src.length; j++) { //遍历旧的Entry数组  
        Entry<K, V> e = src[j];             //取得旧Entry数组的每个元素  
        if (e != null) {  
            src[j] = null;//释放旧Entry数组的对象引用(for循环后,旧的Entry数组不再引用任何对象)  
            do {  
                Entry<K, V> next = e.next;  
                int i = indexFor(e.hash, newCapacity); //!!重新计算每个元素在数组中的位置  
                e.next = newTable[i]; //标记[1]  
                newTable[i] = e;      //将元素放在数组上  
                e = next;             //访问下一个Entry链上的元素  
            } while (e != null);  
        }  
    }  
}  

static int indexFor(int h, int length) {  
    return h & (length - 1);  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

扩容的方式是新建一个newTab,是oldTab的2倍。遍历oldTab,将oldTab赋值进对应位置的newTab。与ArrayList中的扩容逻辑基本一致,只不过ArrayList是当前容量+(当前容量>>1)。

JDK1.8实现resize()方式

/**
 * 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.
 *
 * @return the table
 */
final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    if (oldCap > 0) {
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {               // zero initial threshold signifies using defaults
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
                oldTab[j] = null;
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { // preserve order
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    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;
                    }
                }
            }
        }
    }
    return newTab;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

更多互联网与金融技术精华:http://www.moxianbin.com/

 

Proteus下载安装快速入门:30分钟掌握全过程 手把手教你完成proteus下载安装,从环境配置到首次运行一气呵成,适合电子设计新手快速掌握仿真工具的核心操作步骤。 阅读详情

相关推荐

ArcMap安装与配置全攻略:从下载到实战应用

本文提供了ArcMap 10.4.1从系统准备、详细安装到破解激活的完整指南,并包含首次启动的界面介绍与一个实战GIS分析项目。针对初学者,文章强调了在ArcGIS Pro成为趋势的当下,学习经典ArcMap对于理解核心概念和兼容现有工作流仍有重要价值,帮助用户避开安装常见陷阱,快速上手实战应用。

weixin_29200741的博客 340

HashMap源码分析之Hash冲突的解决

版本:jdk.18 src HashMap是java中实现hash算法的数据结构,hash算法是将给定对象经过hash算法,转化成一串数字。hash算法的实现有很多种,设计一个hash算法需靠考虑比较重要的一点是其计算的效率。 我们都知道,Java中的Object对象中有equals、hashCode、clone等方法,其他所有对象均继承Object方法。我们来看String对象是如何实现的has...

努力奋斗 950

【脑电分析系列】第7篇:频域分析基石 — 功率谱密度(PSD)的计算与常见方法对比

本文探讨了脑电图(EEG)频域分析的核心方法——功率谱密度(PSD)。通过对比基于快速傅里叶变换的周期图法和更稳健的Welch's方法,指出后者通过分段、加窗和平均处理,能有效降低估计方差,更适合分析非稳态的脑电信号。文章详细解析了关键参数设置对频率分辨率和统计稳定性的影响,并提供了Python计算实现。PSD分析将复杂的脑电信号转换为直观的频域特征,为研究认知功能和神经疾病提供重要依据。

qq_32516809的博客 1805

HashMap中的hash()方法是如何解决哈希冲突的

通过源码深度解析HashMap中hash()方法是如何解决哈希冲突的

理想万岁万万岁的博客 266

思科—OSPF多区域配置实验

实验目的:配置OSPF多区域,使得不同网段的PC互相ping通。 网络拓扑如下: R0的配置 Router>en Router#conf t Router(config)#int g0/1 Router(config-if)#ip add 192.168.1.1 255.255.255.0 Router(config-if)#no shut Router(config-if)#exit Router(config)#int g0/0 Router(config-if)#ip add 192.168.

m0_46237205的博客 1万+

AIDL HAL服务从零到一:构建现代Android硬件抽象层

本文详细介绍了从零开始构建现代Android AIDL HAL服务的完整流程。通过定义接口、实现服务逻辑、配置构建与VINTF清单,并最终集成到系统镜像,开发者可以掌握利用AIDL替代传统HIDL来开发硬件抽象层的核心方法。文章重点解析了AIDL HAL的创建流程,并对比了其与HIDL在语法、工具链和集成方式上的优势,帮助开发者高效构建稳定的硬件接口。

weixin_29174141的博客 145

hashmap hash冲突怎么解决_HashMap怎么解决 hash冲突问题

class HashMap extends AbstractMapHashMap put()HashMap get()1.put()HashMapput()方法源码如下:public V put(K key, V value) {if (key == null)return putForNullKey(value);int hash = hash(key.hashCode());int i ...

weixin_39968309的博客 713

MQTT与物联网平台(一):基础知识和设备接入物联网平台的实现(以华为云为例)

本文简单介绍了MQTT的基础知识和使用方法,以蓝牙WIFI双模芯片W801作为硬件设备,接入到华为云。

weixin_50622833的博客 1万+

Java——HashMap中的冲突问题及hashCode与equals方法的重写

2.如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到 下一个空位置,插入新元素。3.采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他 元素的搜索。,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。不同的关键字通过相同的哈希函数有可能计算出相同的哈希地址,这种情况叫做哈希冲突或者哈希碰撞。* 实例内部类中包含两个this,一个是外部类的this,一个是自己的this。

申俏雅的博客 1888

【三维重建】基于多视角图像的三维重建

基于多视角图像的三维重建》

m0_64446860的博客 8761

npm报错 npm WARN deprecated....的问题解决方式

报错 :npm WARN deprecated … 现象:无法进行有效的vue项目的部署以及npm install 命令的执行。 原因一:版本问题 说明:由于npm的版本过低或者过高导致的报错 检查版本: npm -v 如果版本是比较旧的,或者是最新的,这里可以进行对npm的更新和回退。 更新npm版本: npm updated -d 查看可以更新的版本 npm install -g npm 默认安装最新版本 安装回退指定的版本: npm updated -d 查看所有的版本 npm -g i.

任聪聪的博客 16万+

Java 基础学习(十四)Map集合与Set集合

3、如果两个对象被equals()方法判断为不相等,不强制要求它们的hashCode()方法返回不同的哈希码,但是开发者应该了解,返回不同的哈希码有利于提高哈希表的性能。Map接口是一种双列集合。此处需要注意,HashMap并不会直接使用开发者指定的长度作为内部数组的长度,而是会通过一个内部方法,计算大于开发者指定长度的最小的2的幂作为内部数组的长度。4、链地址法:将Hash表的每个单元作为链表的头节点,所有Hash地址为i的元素构成一个同义词链表,即发生冲突时就把该元素链接在该单元为头节点的链表的尾部。

2301_79227925的博客 1192

19 04-读取DTC快照信息

为了方便找到故障的原因,车厂一般会在诊断调查表中定义一些信息作为快照信息,例如故障发生时间、电压、行驶里程数、车速等。在对应故障发生时,ECU端要记录发生故障时的快照信息,客户端可以通过此服务检索客户端定义的DTCMaskRecord的捕获DTC Snapshot记录号以及DTCSnapshot记录数据。通过查找故障发生时刻的这些数据,来分析故障原因。

诊断协议那些事儿's blog 5146

第十三章_数据结构与集合源码二

因为一个HashMap的table数组一般不会特别大,至少在不断扩容之前,那么table.length-1的大部分高位都是0,直接用hashCode和table.length-1进行&运算的话,就会导致总是只有最低的几位是有效的,那么就算你的hashCode()实现的再好也难以避免发生碰撞,这时让高位参与进来的意义就体现出来了。那么发生碰撞冲突时怎么办?因为如果数组的长度为2的n次幂,那么table.length-1的二进制就是一个高位全是0,低位全是1的数字,这样才能保证每一个下标位置都有机会被用到。

m0_75210916的博客 1263

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

计算机控制技术及应用

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

HashMap源码解读,面试常考知识点速通!

通过对HashMap源码的简要解读,我们可以了解到其内部实现采用数组+链表/红黑树的方式,通过哈希算法将键映射到具体的桶中。在插入元素时,会根据桶中的结构选择合适的方式进行插入。同时,HashMap具有动态扩容机制,当元素个数超过一定阈值时,会触发扩容操作。深入了解这些源码细节有助于更好地理解HashMap的工作原理。好了,以上就是本文的全部内容,如有问题欢迎留言讨论。我是chowley,一个专注互联网技术和软件质量保障领域的博主,我们下次再见!

chowley的博客 606

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

java集合框架之Map系列

快速查找:HashMap(无需排序)。保持插入/访问顺序:LinkedHashMap。键排序需求:TreeMap。高并发场景:ConcurrentHashMap。缓存临时数据:WeakHashMap。枚举键:EnumMap。对象地址比较:IdentityHashMap。通过理解各Map实现类的内部机制,可针对具体场景选择最合适的实现,优化性能和功能需求。

qq_39126115的博客 878

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java集合类学习

以下基于jdk1.8 一、 集合类关系图   1. 接口关系图   2.集合中的类,(不包含线程安全的) 二、ArrayList 1.类定义 /** * 用“可伸缩数组”来实现List接口。实现了所有List接口中的方法,并且允许存放所有元素,包括Null。 * 除了实现了List接口,本类还是提供操作数组大小的方法。(本类和Vector类似,只是本类是非同步...

weixin_30278311的博客 142

Java集合框架-搬运工

集合框架的一些源码解析ArrayList解析继承关系成员变量构造方法 这里就不记录一些面试题了。。如果能够理解源码那什么牛鬼蛇神面试题都应该不在话下了 看源码的话,主要还是三个方面吧 继承结构 构造方法 常用方法 ArrayList解析 ArrayList的特点: 基于数组实现 可以动态调整容量 有序 元素可以为null 非线程安全 查询快,增删慢 占用空间更小(对比LinkesList) 继承关系 从ArrayList的源码中也可以看到,ArrayList继承了AbstractList,实现了

weixin_38147296的博客 886

详解Map集合(重点HashMap)

HashMap 数据结构为数组+链表中增加了红黑树,其中:链表的节点存储的是一个 Entry 对象,每个Entry 对象存储四个属性(hash,key,value,next)如图所示。

weixin_52293201的博客 1351

了解Java集合原理

Java集合容器概述 1.什么是集合 集合就是一个放数据的容器,准确的说就是放数据对象引用的容器 集合类存放的都是数据的引用,而非数据本身 集合主要有三种 set、list、map list 接口的特点是有序且可以重复 set接口的特点是无序且不可重复 ArrayList和Linkedlist是list接口的实现类 Hashset 和Treeset是set接口的实现类 HashMap和TreeMap是Map接口的实现类 Collection维护的是单列集合 Map是一个双列集合,用于存储具有Key Va

qq_56671867的博客 284

Java集合框架体系总结

Java集合框架核心摘要(149字) Java集合分为单列(Collection)和双列(Map)两大体系。单列集合包含: List:有序可重复,ArrayList(数组)随机访问快,LinkedList(链表)头尾操作快 Set:无序不重复,HashSet最快,LinkedHashSet保序,TreeSet自动排序 Queue:ArrayDeque替代Stack,PriorityQueue优先级队列 Map以键值对存储,HashMap最快,LinkedHashMap保序,TreeMap按键排序,Concu

程序吟游的博客 4650

day8--java高级编程:数据结构与集合源码

数据结构与集合源码 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 数据结构剖析 我们举一个形象的例子来理解数据结构的作用: 战场:程序运行所需的软件、硬件环境 敌人:项目或模块的功能需求 指挥官:编写程序的程序员 士兵和装备:一行一行的代码 战术和策略:数据结构 上图:没有战术,打仗事倍功半 上图:有战术,打仗事半功倍 总结:简单来说,数据结构,就是一种程序设计优化的方法论,研究数据的逻辑结构和物理结构以及它们之间相互关系,

aa35434的博客 1282

八股 - java集合

原因:线程1先进性扩容,桶2中有A->B元素,将A重新计算分配到了其他桶,此时还未对B进行计算分配,线程2开始了扩容,此时线程2不知道线程1对A进行了什么操作,看到的是桶2只有B->null的元素,于是对B进行扩容操作,重新分配桶,线程2扩容结束后线程1继续进行对B未完成的扩容操作,线程1并不知道B已经分配了,于是重新进行计算分配,因为头插入法导致后来B插入到了A之前,也就是B指向了A B->A,而此时对于之前的旧操作A仍然指向B,于是形成死循环B->A->B,无法get到值而且死循环会导致CPU爆满。

qq_53601740的博客 816

JAVA集合听课笔记

java常用集合类 List接口的方法有: list的三种遍历方式: 集合的理解和好处 数组的不足 动态保存多个对象 多种操作方法 使得代码简洁 集合主要是两种:单列集合,双列集合 collention接口有两个重要的子接口,其实现子类是单列集合 Map接口的实现子类的双列集合 注意:idea在debug默认情况下,显示的数据是简化后的,如果希望看到完整的数据,需要做设置,被阉割的数据 Array’List扩容机制 无参构造器扩容 第一次扩容为10,第二次1.5倍扩容

博客 999

HashMap的工作原理(二):HashMap中的数据结构与原理

1、哈希表概述在了解什么是HashMap之前,我们首先要了解哈希表(Hash table):哈希表(hash table) 也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存存放一张大的哈希表.首先,与哈希表进行区别,我们要了解一下其他数据结构在新增、查找等基础操作的执行性能. 数组:数组采用一段连续的存储单元来进行数据存储,对于指定...

十指波课堂的博客 238

【Java面试集合】hashmap底层原理

1.什么是集合 集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection()分别是java.util.List和java.util.Set。其中,List的特点是元素有序、元素可重复。Set的特点是元素无序,而且不可重复。List接口的主要实现类有java.util.ArrayList和java.util.LinkedList,Set接口的主要实现类有java.util.HashSet和java.util.TreeSet)和双列集合java.util.Map 2.单例集合

csdn_667的博客 803
上一篇: HashMap分析之红黑树树化过程
下一篇: [Java]Object有哪些公用方法?
javaPie
博客等级 码龄16年 1171粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值