大庆市网站建设_网站建设公司_电商网站_seo优化
2025/12/17 11:28:53 网站建设 项目流程

Java Map 详解:原理、实现与使用场景

一、介绍

Map 是 Java 集合框架(java.util)中键值对(Key-Value)形式的集合接口,与 List/Set 并列(继承自Collection的父接口Iterable,但不直接继承Collection)。核心特征是:键(Key)唯一且无序(部分实现有序),值(Value)可重复,通过键快速查找值,是日常开发中存储关联数据的核心工具。

特性:
  1. 键值对映射:每个 Key 对应唯一的 Value,Key 不允许重复(若重复插入,新 Value 会覆盖旧 Value);
  2. Key 不可变性:作为 Key 的对象需重写hashCode()equals()方法(保证哈希一致性),且建议使用不可变类型(如 String、Integer),避免修改后哈希值变化导致无法查找;
  3. 支持 null:不同实现类对 null 的支持不同(如 HashMap 允许 1 个 null Key + 多个 null Value,Hashtable 不允许 null);
  4. 无序性(默认):大部分 Map 实现(如 HashMap)不保证键值对的存储 / 遍历顺序,有序实现需显式指定(如 TreeMap、LinkedHashMap)。

二、Map 接口核心方法

Map 定义了键值对操作的核心方法,覆盖增删改查、遍历等场景:

方法作用
V put(K key, V value)添加 / 替换键值对:Key 不存在则新增,存在则替换 Value,返回旧 Value(无则返回 null)
V get(Object key)根据 Key 获取 Value,Key 不存在返回 null
V remove(Object key)删除指定 Key 的键值对,返回被删除的 Value(无则返回 null)
boolean containsKey(Object key)判断是否包含指定 Key
boolean containsValue(Object value)判断是否包含指定 Value(需遍历,效率低)
int size()返回键值对数量
boolean isEmpty()判断是否为空
void clear()清空所有键值对
Set<K> keySet()返回所有 Key 的 Set 集合(视图,修改会同步到原 Map)
Collection<V> values()返回所有 Value 的 Collection 集合(视图)
Set<Map.Entry<K,V>> entrySet()返回键值对(Entry)的 Set 集合(遍历最优方式)

三、Map 主要实现类

Java 提供了多款 Map 实现类,适配不同的性能、有序性、并发场景,核心如下:

1. HashMap(最常用)

底层实现:JDK 8 前 = 数组(哈希桶)+ 链表;JDK 8 后 = 数组 + 链表 / 红黑树(链表长度 ≥8 转红黑树,≤6 转回链表)。

补充:

HashMap 的底层由「哈希桶数组」+「链表 / 红黑树」组成,核心设计目标是:通过哈希算法将 Key 映射到数组下标,实现 O (1) 级别的快速存取;通过链表 / 红黑树解决「哈希冲突」(不同 Key 哈希值相同的情况)。

  • 哈希桶数组(table):默认初始长度 16(2 的幂),每个下标对应一个「桶」,桶内存储链表或红黑树;
  • 链表:当多个 Key 哈希到同一桶时,先以链表形式存储;
  • 红黑树:当链表长度 ≥8 且数组长度 ≥64 时,链表转为红黑树(查询性能从 O (n) 优化为 O (log n));当红黑树节点数 ≤6 时,转回链表(减少红黑树维护开销)。
红黑树:

红黑树是带红 / 黑颜色标记的自平衡二叉查找树,也是二叉树的一种,不过有5条规则对树的高度进行限制,增删改查的时间复杂度稳定在O(logn)

补充一下那5条规则:

(1)每个节点只能为黑色或者红色

(2)根节点必须为黑色

(3)所有“空叶子节点”都是黑色

(4)红色节点的父节点和子节点都必须为黑色(你也可以这样理解,不能连续俩红色节点)

(5)从任意节点到它自己所有叶子节点(在红黑树中这个叶子节点就是指的空叶子节点)的路径中,黑色节点的数量完全相同

规则是为了做什么?

保证树的结构不会退化成链表,同时保证增删查改始终是 O (log n)

(补:最长路径的长度 ≤ 2 × 最短路径的长度,两者的差值最大为 最短路径的长度)

什么是桶?

桶就是 HashMap 哈希桶数组里的一个存储单元,负责接收通过哈希计算分配过来的键值对节点,解决哈希冲突的链表 / 红黑树也都是在桶内部形成的。

简单举个例子:

把 HashMap 想象成一个带编号的快递柜,这个快递柜的每个独立格子就是一个

  1. 快递柜 = 哈希桶数组(table)快递柜有很多个格子,每个格子都有自己的编号(比如 0、1、2…15),对应 HashMap 数组的索引
  2. 桶 = 快递柜的单个格子每个格子(桶)的作用是存放 “属于自己” 的快递。在 HashMap 中,通过哈希计算,会把键值对节点分配到对应编号的桶里。
  3. 哈希冲突 = 一个格子里放多个快递
    • 理想情况:一个快递(节点)对应一个格子(桶),取件时直接按编号找,速度飞快(对应 HashMap 的 O (1) 存取)。
    • 现实情况:可能出现多个快递被分配到同一个格子(不同 Key 计算出相同的数组索引),这就是哈希冲突。这时,HashMap 会在这个桶里用链表把这些节点串起来;如果链表太长(≥8),就会变成红黑树,提升查询效率。
核心特点:
  • 存取效率高(平均 O (1) 时间复杂度),基于哈希表快速定位;
  • 无序(存储顺序 ≠ 插入顺序);
  • 允许 1 个 null Key、多个 null Value;
  • 非线程安全(多线程操作可能导致死循环、数据丢失);
  • 初始容量 16,负载因子 0.75(扩容阈值 = 容量 × 负载因子,默认 12),扩容时容量翻倍,且重新哈希。
机制详解:
哈希计算与索引定位:

HashMap 高效存取的核心是「将 Key 映射到数组下标」,分为两步:

1.Key 的哈希值计算

为了减少哈希冲突,HashMap 对 Key 的hashCode()做了二次哈希(扰动函数):

staticfinalinthash(Objectkey){inth;// 核心逻辑:key.hashCode() ^ (h >>> 16)return(key==null)?0:(h=key.hashCode())^(h>>>16);}
  • 作用:将 Key 的哈希值高 16 位与低 16 位异或,混合高低位特征,减少哈希冲突(尤其数组长度较小时,仅低几位参与取模,混合后能利用高位信息);
  • null Key 处理:hash 值固定为 0,因此 null Key 始终映射到数组索引 0。

2.数组索引计算

通过哈希值计算数组下标,利用「位运算替代取模」提升性能(仅当数组长度为 2 的幂时生效):

java

// i = 哈希值 & (数组长度 - 1)intindex=hash&(table.length-1);
  • 示例:数组长度 16(二进制 10000),table.length - 1 = 15(二进制 01111);哈希值与 15 按位与,等价于hash % 16,但位运算更快。

  • 为什么数组长度是 2 的幂?

    → 保证hash & (length-1)等价于取模,且位运算效率远高于取模;

    → 扩容时,节点新索引要么不变,要么 = 原索引 + 原数组长度(简化扩容迁移逻辑)。

扩容机制:

条件:

  • 首次put时,table为 null,初始化数组(默认长度 16,threshold=16×0.75=12);
  • 后续put时,若size > threshold,触发扩容;
  • 链表长度≥8 但数组长度 < 64 时,优先扩容(而非树化)。

步骤:

// 1. 计算新容量:原容量翻倍(始终保持2的幂)intnewCap=oldCap<<1;// 如16→32,32→64...// 2. 计算新扩容阈值:newThr = newCap × loadFactorintnewThr=oldThr<<1;// 3. 创建新数组(长度newCap)Node<K,V>[]newTab=(Node<K,V>[])newNode[newCap];table=newTab;// 4. 迁移原数组节点到新数组for(intj=0;j<oldCap;++j){Node<K,V>e;if((e=table[j])!=null){table[j]=null;// 释放原数组引用(帮助GC)// 情况1:桶内仅一个节点,直接计算新索引并放入if(e.next==null)newTab[e.hash&(newCap-1)]=e;// 情况2:桶内是红黑树,拆分红黑树并迁移elseif(einstanceofTreeNode)((TreeNode<K,V>)e).split(this,newTab,j,oldCap);// 情况3:桶内是链表,拆分链表(优化:无需重新哈希,仅判断高位)else{// 链表拆分规则:新索引 = 原索引 或 原索引 + oldCapNode<K,V>loHead=null,loTail=null;// 原索引节点Node<K,V>hiHead=null,hiTail=null;// 原索引+oldCap节点Node<K,V>next;do{next=e.next;// 核心判断:哈希值的第n位(oldCap的二进制位)是否为0if((e.hash&oldCap)==0){// 第n位为0 → 新索引=原索引if(loTail==null)loHead=e;elseloTail.next=e;loTail=e;}else{// 第n位为1 → 新索引=原索引+oldCapif(hiTail==null)hiHead=e;elsehiTail.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;}}}}

使用示例

Map<String,Integer>hashMap=newHashMap<>();hashMap.put("Java",1);hashMap.put("Python",2);Integervalue=hashMap.get("Java");// 获取值:1hashMap.put("Java",3);// 替换值,旧值 1 被覆盖
各操作逻辑:

1.存

先定位桶 → 无冲突则新增节点 → 有冲突则按链表 / 红黑树处理 → 替换重复 Key 的 Value → 检查扩容。

2.取

定位桶 → 桶头匹配直接返回 → 红黑树 / 链表遍历匹配 → 未找到返回 null。

3.删

定位待删除节点 → 按链表 / 红黑树规则删除 → 更新 size 和 modCount。

2. LinkedHashMap

底层实现:HashMap + 双向链表(维护插入 / 访问顺序)。

补充:

LinkedHashMap 完全复用 HashMap 的哈希桶数组、节点哈希 / 扩容 / 树化等逻辑,仅通过「双向链表」改造节点结构、新增头尾指针,实现有序性。

  • 哈希桶层:和 HashMap 完全一致,负责通过哈希快速定位节点,解决哈希冲突(链表 / 红黑树);
  • 双向链表层:所有节点通过before/after指针串联,head指向最早节点,tail指向最新节点,专门维护遍历顺序;
  • 节点复用:LinkedHashMap 的 Entry 继承 HashMap.Node,因此哈希桶里的节点同时属于「哈希链表 / 红黑树」和「双向链表」,一个节点两个 “身份”。
什么是节点?

在 LinkedHashMap(以及 HashMap)中,节点(Node/Entry)是存储「键值对(Key-Value)」的最小单元 —— 就像快递包裹本身,而桶是放包裹的格子、双向链表是串包裹的绳子。

举个具体的例子:

比如你往 LinkedHashMap 里存put("手机", 1999)put("耳机", 299)put("充电器", 99)

  • 每个键值对对应一个「节点」:

    节点 1:Key = 手机,Value=1999;

    节点 2:Key = 耳机,Value=299;

    节点 3:Key = 充电器,Value=99。

  • 这些节点会按哈希规则被分配到不同的桶(比如手机→3 号格、耳机→5 号格、充电器→3 号格):

    3 号桶里有两个节点(手机 + 充电器),用链表串起来;5 号桶只有耳机节点。

  • 同时,这三个节点会被双向链表串成head→手机→耳机→充电器→tail(插入顺序);如果调用get("手机"),节点 1 会被挪到尾部,链表变成head→耳机→充电器→手机→tail(访问顺序)。

核心特点:

  • 继承 HashMap 的所有特性,额外保证「有序性」;
  • 有序模式:
    • 插入顺序(默认):遍历顺序 = 插入顺序;
    • 访问顺序:调用get()/put()后,该键值对移至链表尾部(可实现 LRU 缓存);
  • 非线程安全,性能略低于 HashMap(维护链表开销)。

使用示例(LRU 缓存)

// 初始容量16,负载因子0.75,访问顺序模式Map<String,Integer>lruMap=newLinkedHashMap<>(16,0.75f,true);lruMap.put("a",1);lruMap.put("b",2);lruMap.get("a");// 访问后,"a" 移至尾部// 遍历顺序:b → a(访问顺序)for(Map.Entry<String,Integer>entry:lruMap.entrySet()){System.out.println(entry.getKey());}

3. TreeMap

底层实现:红黑树(自平衡的二叉查找树)。

核心特点:

  • 有序:默认按 Key 的自然顺序(如 Integer 升序、String 字典序),或自定义 Comparator 排序;
  • 无 null Key(会抛 NullPointerException),允许 null Value;
  • 存取效率 O (log n)(红黑树查找 / 插入),低于 HashMap;
  • 非线程安全;
  • 适合需要排序的场景(如按 Key 范围查询)。

使用示例(自定义排序)

// 按 Key 降序排序Map<Integer,String>treeMap=newTreeMap<>((k1,k2)->k2-k1);treeMap.put(3,"c");treeMap.put(1,"a");treeMap.put(2,"b");// 遍历顺序:3 → 2 → 1for(Integerkey:treeMap.keySet()){System.out.println(key);}

4. Hashtable(古老的线程安全实现)

底层实现:数组 + 链表(JDK 8 未优化红黑树)。

补充:

Hashtable 无红黑树优化(全程仅数组 + 链表),线程安全通过「方法级synchronized」实现,是典型的 “简单粗暴” 的线程安全哈希表设计。

  • 哈希桶数组:默认初始长度 11(非 2 的幂,区别于 HashMap),每个下标对应一个桶,桶内存储链表;
  • 链表:所有哈希冲突的节点(Key 哈希到同一桶)通过next指针串联,无红黑树优化,链表过长时查询性能退化至 O (n);
  • 线程安全:所有核心方法(put/get/remove)都加synchronized锁,锁粒度为整个 Hashtable 对象。

核心特点

  • 线程安全(方法级synchronized锁),但锁粒度大,性能差;
  • 不允许 null Key/Value(抛 NullPointerException);
  • 初始容量 11,负载因子 0.75,扩容时容量 = 原容量 ×2 +1;
  • 基本被 ConcurrentHashMap 替代,仅兼容旧代码时使用。
机制详解:
哈希计算与扩容:
  1. Key 的哈希计算(无扰动优化)

    Hashtable 的哈希计算逻辑简单,无 HashMap 的 “高低位异或” 扰动优化,且直接使用key.hashCode()(不允许 null Key):

    // 计算Key的哈希值(简化版)inthash=key.hashCode();// 计算数组索引(取模,而非位运算)intindex=(hash&0x7FFFFFFF)%table.length;
  2. 扩容机制(区别于HashMap):

    Hashtable 扩容触发后,新容量 = 原容量 × 2 + 1(而非 HashMap 的翻倍)

    // 1. 计算新容量:原容量 ×2 +1(如 11→23,23→47...)intnewCapacity=table.length*2+1;// 2. 计算新扩容阈值:newThr = (int)(newCapacity × loadFactor)intnewThreshold=(int)(newCapacity*loadFactor);// 3. 创建新数组(长度newCapacity)Entry<?,?>[]newTable=newEntry<?,?>[newCapacity];// 4. 迁移原数组节点到新数组(重新计算索引,拷贝链表)for(inti=0;i<table.length;i++){Entry<K,V>e=(Entry<K,V>)table[i];if(e!=null){table[i]=null;// 释放原数组引用do{Entry<K,V>next=e.next;// 重新计算新索引(取模)intindex=(e.hash&0x7FFFFFFF)%newCapacity;e.next=(Entry<K,V>)newTable[index];newTable[index]=e;e=next;}while(e!=null);}}// 5. 替换数组和阈值table=newTable;threshold=newThreshold;

    差异总结:

    • 容量增长规则:2n+1(保证素数,理论减少哈希冲突,但无实际性能优势),HashMap 是2n(2 的幂,位运算优化);
    • 索引重计算:每次扩容都需对所有节点重新取模,无 HashMap 的 “高位判断” 优化,扩容开销更大;
    • 触发条件:count ≥ threshold(HashMap 是size > threshold),更早触发扩容。

5. ConcurrentHashMap(并发安全)

底层实现:JDK 8 前 = 分段锁(Segment 数组 + HashMap);JDK 8 后 = 数组 + 链表 / 红黑树 + CAS + synchronized(锁哈希桶,粒度更细)。

补充:
  • 哈希桶层:与 HashMap 一致(数组长度为 2 的幂,链表≥8 转红黑树),但数组 / 节点关键字段(table/val/next)用volatile保证多线程可见性;
  • 并发控制层:
    • 无竞争时:用 CAS 操作新增节点(无锁);
    • 有竞争时:对「单个哈希桶」加synchronized锁(仅锁住冲突的桶,其他桶可并行操作);
    • 扩容时:用ForwardingNode标记桶状态,多线程协同扩容(避免单线程扩容瓶颈);
  • 节点特性:Node节点的val/nextvolatile,保证修改后其他线程能立即感知。

核心特点:

  • 线程安全(高并发):JDK 8 后锁粒度为「单个哈希桶」,并发性能远高于 Hashtable;
  • 支持 1 个 null Key(JDK 8 后)、多个 null Value;
  • 存取效率接近 HashMap(并发场景下);
  • 迭代器是 “弱一致性”,不会抛ConcurrentModificationException
  • 适合高并发读写的场景(如分布式缓存、业务核心数据存储)。

扩容机制(多线程协同)

size > 容量 × 负载因子(默认初始容量 16,负载因子 0.75,阈值 12),且当前数组(table)无其他扩容操作时触发。

ConcurrentHashMap 扩容由「触发线程 + 其他访问线程」协同完成,避免单线程扩容瓶颈:

  1. 触发条件:size > sizeCtl(同 HashMap);
  2. 扩容流程:
    • 创建nextTable(容量翻倍);
    • 遍历table桶,将桶节点迁移到nextTable
    • 迁移时,将原桶头节点替换为ForwardingNode(标记扩容中);
    • 其他线程访问该桶时,检测到ForwardingNode,会暂停当前操作,协助扩容;
  3. 核心优势:多线程并行迁移不同桶,大幅提升扩容效率。

使用示例

Map<String,String>concurrentMap=newConcurrentHashMap<>();// 多线程安全写入newThread(()->concurrentMap.put("thread1","data1")).start();newThread(()->concurrentMap.put("thread2","data2")).start();// 安全读取System.out.println(concurrentMap.get("thread1"));

6. Properties(配置文件专用)

底层实现:继承 Hashtable,Key/Value 均为 String 类型。

补充:

Properties 完全复用 Hashtable 的哈希表核心逻辑(数组 + 链表、方法级 synchronized 锁、禁止 null 值),仅在其基础上增加「Key/Value 强制为 String 类型」和「配置文件读写」的扩展方法。

核心存储层:完全复用 Hashtable 的table数组(初始容量 11,扩容规则 2n+1)、Entry 链表节点,线程安全通过方法级synchronized实现;

扩展层:

  • 类型约束:Key/Value 实际使用时强制为 String(虽底层仍存储 Object,但setProperty()/getProperty()限定为 String);
  • 配置继承:通过defaults实现配置复用(当前配置无 Key 时,从默认配置集查找);
  • IO 能力:load()/store()方法解析 / 生成.properties格式的配置文件(键值对以key=value换行存储)。

核心特点:

  • 专为读取配置文件(.properties)设计,支持load()/store()方法读写文件;
  • 线程安全(继承 Hashtable 的 synchronized 方法);
  • 常用场景:读取系统配置、项目配置文件。
操作原理:

配置文件加载(load ())

load()是 Properties 最核心的扩展方法,用于从.properties文件 / 输入流解析键值对:

// 示例:加载配置文件Propertiesprops=newProperties();props.load(newFileInputStream("config.properties"));

解析:

  1. 按行读取输入流,忽略注释行(以#/!开头)和空行;
  2. 解析每行的key=value格式(支持:/ 空格 作为分隔符),去除首尾空格;
  3. 调用put(key, value)(继承 Hashtable)将键值对存入哈希表;
  4. 全程加synchronized锁,保证线程安全。

配置获取(getProperty ())

getProperty()是 String 专属的获取方法,支持默认配置集查找:

Stringurl=props.getProperty("db.url");// 带默认值:若Key不存在,返回默认值"jdbc:mysql://localhost"Stringurl=props.getProperty("db.url","jdbc:mysql://localhost");

查找逻辑:

  1. 调用 Hashtable 的get(key)获取值,强转为 String;
  2. 若值为 null 且defaults不为 null,递归从defaults中查找;
  3. 若仍为 null,返回指定的默认值(或 null)。

配置存储(store ())

store()用于将配置写入文件 / 输出流,生成标准.properties文件:

props.store(newFileOutputStream("config.properties"),"DB Config");

写入逻辑:

  1. 先写入注释(可选)和当前时间戳;
  2. 遍历哈希表的 Entry 链表,按key=value格式逐行写入;
  3. 全程加synchronized锁,保证写入过程不被打断。

基础操作(put/remove)

Properties 未重写 Hashtable 的put()/remove()方法,完全复用其逻辑:

  • setProperty(key, value)本质是调用put(key, value),仅限定参数为 String;
  • 所有操作均加synchronized锁,线程安全但并发性能差(同 Hashtable)。

使用示例

Propertiesprops=newProperties();// 读取配置文件props.load(newFileInputStream("config.properties"));Stringurl=props.getProperty("db.url");// 获取配置值

四、Map 常见使用场景

场景推荐实现类
日常开发、无排序、高读写性能HashMap
需要有序(插入 / 访问顺序)、LRU 缓存LinkedHashMap
需要按 Key 排序、范围查询TreeMap
高并发读写、线程安全ConcurrentHashMap
配置文件读写Properties
旧代码兼容、低并发线程安全Hashtable

五、Map 遍历方式(性能对比)

Map 遍历的核心是操作entrySet()/keySet()/values(),推荐优先级:

entrySet 遍历(最优):直接获取键值对,无需二次查询,性能最高;

for(Map.Entry<String,Integer>entry:map.entrySet()){Stringkey=entry.getKey();Integervalue=entry.getValue();}

迭代器遍历(支持删除):适合遍历中删除元素,避免ConcurrentModificationException

Iterator<Map.Entry<String,Integer>>it=map.entrySet().iterator();while(it.hasNext()){Map.Entry<String,Integer>entry=it.next();if(entry.getValue()==2){it.remove();// 安全删除}}

keySet + get () 遍历(低效):需二次哈希查询,性能最差,不推荐;

for(Stringkey:map.keySet()){Integervalue=map.get(key);// 额外哈希查询}

Lambda 遍历(简洁):JDK 8+ 支持,代码简洁,性能接近 entrySet;

map.forEach((key,value)->System.out.println(key+":"+value));

六、注意事项

  1. Key 的哈希与相等性:
    • 自定义对象作为 Key 时,必须重写hashCode()equals()(保证相同对象哈希值相同,不同对象哈希值尽量不同);
    • 避免使用可变对象作为 Key(如 ArrayList),修改后哈希值变化会导致无法查找。
  2. HashMap 扩容优化:
    • 已知元素数量时,提前指定初始容量(如new HashMap<>(100)),避免频繁扩容(扩容需重新哈希,开销大);
    • 负载因子默认 0.75 是性能与内存的平衡,无需轻易修改。
  3. 并发安全:
    • HashMap/LinkedHashMap/TreeMap 非线程安全,多线程修改需手动加锁(如Collections.synchronizedMap()),或直接使用 ConcurrentHashMap;
    • ConcurrentHashMap 不支持null Key(JDK 7)/ 支持 1 个 null Key(JDK 8+),需注意空值处理。
  4. TreeMap 排序:
    • 自定义对象作为 Key 时,需实现Comparable接口,或创建 TreeMap 时指定 Comparator,否则抛ClassCastException

七、总结

Map 是 Java 中存储键值对的核心集合,核心实现类各有侧重:

  • HashMap:性能均衡,适合绝大多数无排序、非并发场景;
  • LinkedHashMap:有序 + HashMap 特性,适合缓存场景;
  • TreeMap:排序 + 范围查询,适合有序键值对场景;
  • ConcurrentHashMap:高并发安全,适合核心业务的并发存储;
  • Properties:配置文件专用,简单易用。

七、总结

Map 是 Java 中存储键值对的核心集合,核心实现类各有侧重:

  • HashMap:性能均衡,适合绝大多数无排序、非并发场景;
  • LinkedHashMap:有序 + HashMap 特性,适合缓存场景;
  • TreeMap:排序 + 范围查询,适合有序键值对场景;
  • ConcurrentHashMap:高并发安全,适合核心业务的并发存储;
  • Properties:配置文件专用,简单易用。

选择时需根据「有序性、并发要求、性能、业务场景」四大维度权衡,同时注意 Key 的不可变性和遍历方式的性能优化。

附表:

JDK 版本核心变化点涉及 Map 实现类详细说明
JDK 1.0初始版本发布Hashtable1. 引入 Hashtable,底层为「数组 + 链表」,方法级synchronized保证线程安全;2. 不支持 null Key/Value,初始容量 11,扩容规则2n+1;3. 无红黑树、无扰动哈希、无并发优化。
JDK 1.2集合框架重构HashMap、TreeMap1. 引入 HashMap,替代 Hashtable 成为非线程安全哈希表首选;- 底层「数组 + 链表」,初始容量 16(2 的幂),负载因子 0.75;- 支持 1 个 null Key、多个 null Value;- 实现扰动哈希(高低位异或)、位运算索引计算;2. 引入 TreeMap,底层红黑树,支持 Key 自然排序 / 自定义排序,无 null Key;3. 引入 LinkedHashMap(HashMap 子类),双向链表维护插入 / 访问顺序。
JDK 1.4配置增强Properties1. 基于 Hashtable 扩展,强化.properties配置文件读写能力;2. 新增loadFromXML()/storeToXML()方法,支持 XML 格式配置。
JDK 5.0泛型支持所有 Map 实现类1. 引入泛型(Map<K,V>),替代原始 Object 类型,避免强制类型转换;2. 优化 TreeMap 比较器,支持Comparator<? super K>泛型约束。
JDK 6.0性能微调HashMap、Hashtable1. 优化 HashMap 哈希算法,减少哈希冲突概率;2. 调整 Hashtable 扩容阈值计算逻辑,提升低容量场景性能。
JDK 7.0并发优化ConcurrentHashMap1. 重写 ConcurrentHashMap,底层「分段锁(Segment)+ HashMap」;- 分段锁粒度为 Segment(默认 16 个),并发度远高于 Hashtable;- 不支持 null Key/Value,避免并发场景空指针歧义;2. HashMap 优化扩容逻辑,减少扩容时的哈希冲突。
JDK 8.0核心重构(里程碑)HashMap、ConcurrentHashMap、LinkedHashMap1. HashMap 重大升级:- 链表长度 ≥8 且数组长度 ≥64 时,链表转红黑树(查询从 O (n)→O (log n));- 红黑树节点数 ≤6 时,转回链表(降低维护开销);- 优化扩容机制,多线程扩容(但仍非线程安全);- 简化扰动哈希逻辑(key.hashCode() ^ (h >>> 16));2. ConcurrentHashMap 重构:- 废弃分段锁,改用「CAS + synchronized 锁单个哈希桶」,并发粒度更细;- 支持 1 个 null Key(区别于 JDK 7),兼容 HashMap 用法;- 引入红黑树优化(同 HashMap);3. LinkedHashMap 优化:- 强化 LRU 场景性能,访问顺序模式下节点迁移效率提升;4. 新增 Lambda 遍历(forEach()方法),简化遍历写法。
JDK 9.0工厂方法增强所有 Map 实现类1. 引入不可变 Map 工厂方法:-Map.of()(最多 10 个键值对)、Map.ofEntries()(不限数量);- 不可变 Map 不支持增删改,无 null Key/Value,性能更高。
JDK 11.0性能与安全优化ConcurrentHashMap、HashMap1. 优化 ConcurrentHashMap 扩容逻辑,多线程协同扩容效率提升;2. 修复 HashMap 极端哈希值下的性能退化问题;3. 增强不可变 Map 的序列化安全性。
JDK 17.0长期支持版优化所有 Map 实现类1. 稳定化不可变 Map 实现,修复多线程下的弱一致性问题;2. 优化 TreeMap 红黑树旋转逻辑,减少排序耗时;3. 废弃 Hashtable 部分过时方法(如elements()),推荐 ConcurrentHashMap 替代。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询