当前位置: 首页 > news >正文

Java集合体系 —— Map篇

        在 Java 集合框架中,Map 接口是与 Collection 接口并列的核心接口,它定义了一组 “键值对(Key-Value)” 形式的集合操作规范。与 Set 的 “去重” 核心价值不同,Map 的核心价值在于 “通过键快速查找值”,并通过不同实现类适配 “高性能查找”“保证插入顺序”“支持排序” 等多样化需求。本文将从 Map 接口概述入手,深入解析 HashMap、LinkedHashMap、TreeMap 三大实现类的底层结构、核心源码、性能特点及适用场景,为实际开发提供选择依据。

    

一、Map 接口概述

Map 接口是 Java 集合框架中独立的接口,不继承自 Collection 接口,其设计初衷是维护一组 “键唯一、值可重复” 的键值对,所有实现类需遵守以下核心规范:

1. 核心特性

  • 键唯一性:集合中不会存在两个通过 equals () 方法判断为 true 的键(具体去重逻辑由实现类决定,如哈希表或比较器)。
  • 值可重复性:不同的键可以对应相同的值,无唯一性要求。
  • 无索引:不支持通过 int 类型索引访问键值对,遍历需依赖键集(keySet ())、值集(values ())或键值对集(entrySet ())。
  • 无序性(默认):除 LinkedHashMap(保证插入顺序)和 TreeMap(保证排序顺序)外,多数实现类(如 HashMap)不保证键值对的存储 / 遍历顺序与插入顺序一致。

2. 主要方法

方法功能核心特性
V put(K key, V value)向集合添加键值对键不存在则添加并返回 null,键存在则覆盖值并返回旧值(键唯一核心)
V remove(Object key)根据键移除键值对键存在则移除并返回对应值,否则返回 null
boolean containsKey(Object key)判断是否包含指定键依赖实现类的查找逻辑(如哈希表查找或红黑树查找)
boolean containsValue(Object value)判断是否包含指定值需遍历值集,性能通常低于 containsKey ()
V get(Object key)根据键获取对应值键存在则返回对应值,否则返回 null
Set<K> keySet()返回所有键的集合返回的 Set 集合特性与实现类的键存储特性一致(如无序 / 有序)
Collection<V> values()返回所有值的集合返回的 Collection 集合支持遍历,值可重复
Set<Map.Entry<K,V>> entrySet()返回所有键值对的集合便于同时遍历键和值,性能优于分别遍历 keySet () 和 get ()
int size()返回键值对个数-
void clear()清空所有键值对-
void putAll(Map<? extends K, ? extends V> m)添加指定 Map 的所有键值对键存在则覆盖值,不存在则新增

Map 接口本身不提供额外排序或顺序保证方法,所有差异化能力(如排序、顺序保证)均由具体实现类扩展。

二、HashMap 详解与源码分析

HashMap 是 Map 接口最常用的实现类,其底层通过哈希表(数组 + 链表 + 红黑树,JDK 1.8+)实现高效的键值对存储与查找,核心优势是 “高性能增删改查”。

1. 底层数据结构

HashMap 的底层结构为 “哈希表”,由数组(称为 “桶”,bucket)、链表和红黑树组成:

  • 数组:存储键值对节点(Node<K,V>),每个数组元素对应一个 “桶”,桶的索引通过键的哈希值计算得出。
  • 链表:当多个键的哈希值计算出相同的桶索引(哈希冲突)时,通过链表存储这些键值对节点;若链表长度超过 8,且数组长度大于 64,则转为红黑树。
  • 红黑树:优化哈希冲突严重时的查询性能,将链表的 O (n) 查询时间复杂度降至 O (log n)。

2. 核心源码分析

(1)构造方法:初始化哈希表

HashMap 的构造方法主要用于初始化数组容量(默认 16)和负载因子(默认 0.75),负载因子用于平衡性能与内存开销:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {// 默认初始容量(16,必须是2的幂)static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;// 默认负载因子static final float DEFAULT_LOAD_FACTOR = 0.75f;// 链表转红黑树的阈值(8)static final int TREEIFY_THRESHOLD = 8;// 存储键值对的数组(桶)transient Node<K,V>[] table;// 空参构造:使用默认容量和负载因子public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR;}// 指定初始容量:使用默认负载因子public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);}// 指定初始容量和负载因子public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " + loadFactor);this.loadFactor = loadFactor;// 计算大于等于initialCapacity的最小2的幂(保证哈希计算均匀)this.threshold = tableSizeFor(initialCapacity);}
}
(2)添加键值对:put (K key, V value)—— 核心逻辑

HashMap 的 put 方法是实现 “键唯一” 和 “高效存储” 的核心,流程包括哈希计算、桶定位、冲突处理和扩容判断:

public V put(K key, V value) {// 调用putVal方法,传入键的哈希值、键、值及默认参数return putVal(hash(key), key, value, false, true);
}// 核心添加逻辑
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;// 1. 若数组未初始化或长度为0,先初始化数组(resize()方法)if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 2. 计算桶索引((n-1) & hash),若桶为空,直接创建新节点放入桶中if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);// 3. 桶不为空,处理哈希冲突else {Node<K,V> e; K k;// 3.1 若桶中第一个节点的键与当前键相同(哈希值+equals()均匹配),记录该节点if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))e = p;// 3.2 若桶中节点是红黑树节点,调用红黑树的插入方法else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);// 3.3 若桶中节点是链表节点,遍历链表else {for (int binCount = 0; ; ++binCount) {// 3.3.1 遍历到链表尾部,创建新节点加入链表if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 3.3.2 若链表长度超过阈值,将链表转为红黑树if (binCount >= TREEIFY_THRESHOLD - 1)treeifyBin(tab, hash);break;}// 3.3.3 遍历中找到键相同的节点,跳出循环if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// 4. 若找到键相同的节点(e != null),根据onlyIfAbsent决定是否覆盖值if (e != null) {V oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e); //  LinkedHashMap重写此方法,用于维护插入顺序return oldValue;}}++modCount; // 修改计数器,用于快速失败机制// 5. 若键值对数量超过阈值(容量*负载因子),触发扩容if (++size > threshold)resize();afterNodeInsertion(evict); // LinkedHashMap重写此方法,用于删除最少使用元素(LRU)return null;
}

关键逻辑:

  1. 哈希计算:通过 hash (key) 方法对键的 hashCode () 进行二次哈希,减少哈希冲突。
  2. 桶定位:通过 (n-1) & hash 计算桶索引,n 为数组长度(2 的幂),保证索引在数组范围内。
  3. 键唯一判断:先比较哈希值,再通过 equals () 方法验证,两者均匹配则视为相同键。
  4. 扩容机制:当键值对数量超过 “容量 * 负载因子” 时,数组容量翻倍(仍为 2 的幂),重新分配所有键值对。
(3)获取值:get (Object key)

get 方法通过键的哈希值定位桶,再遍历链表或红黑树查找对应键值对:

public V get(Object key) {Node<K,V> e;// 调用getNode方法,传入键的哈希值和键return (e = getNode(hash(key), key)) == null ? null : e.value;
}final Node<K,V> getNode(int hash, Object key) {Node<K,V>[] tab; Node<K,V> first, e; int n; K k;// 1. 数组初始化且桶不为空if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {// 2. 检查桶中第一个节点if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))return first;// 3. 桶中节点不止一个,遍历查找if ((e = first.next) != null) {// 3.1 红黑树节点,调用红黑树查找方法if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);// 3.2 链表节点,遍历链表do {if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;
}

3. 性能特点

  • 增删改查:无哈希冲突时,时间复杂度为 O (1);哈希冲突严重时,链表转为红黑树,时间复杂度为 O (log n)。
  • 扩容开销:扩容时需重新计算所有键的桶索引并迁移,元素数量多时开销较大,建议初始化时指定合适容量。
  • 内存占用:哈希表存在负载因子,预留部分空桶,存在少量空间浪费;键为 null 时仅占用一个桶(哈希值视为 0)。
  • 线程安全:非线程安全,多线程并发修改会抛出 ConcurrentModificationException,需通过 Collections.synchronizedMap (new HashMap<>()) 或 ConcurrentHashMap 实现同步。

4. 适用场景

  • 无需保证键值对顺序,仅需通过键快速查找值的场景(如存储用户信息,键为用户 ID,值为用户对象);
  • 频繁执行增删改查操作,对性能要求高的场景;
  • 允许键为 null(仅 1 个)、值为 null 的场景。

三、LinkedHashMap 详解与源码分析

LinkedHashMap 是 HashMap 的子类,其底层在 HashMap 的哈希表基础上,额外维护了一个双向链表,用于记录键值对的插入顺序或访问顺序,核心优势是 “高性能 + 顺序保证”。

1. 底层数据结构

LinkedHashMap 的底层结构为 “哈希表 + 双向链表”:

  • 哈希表:继承自 HashMap,保证增删改查的高效性(同 HashMap)。
  • 双向链表:每个键值对节点(Entry<K,V>)额外存储 prev(前驱)和 next(后继)引用,按插入顺序或访问顺序串联所有节点,确保遍历顺序可控。
  • 节点类型:LinkedHashMap 的 Entry 节点继承自 HashMap 的 Node 节点,新增 prev 和 next 字段:
static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}
}
  • 顺序模式:通过 accessOrder 字段控制顺序(默认 false,按插入顺序;true 时按访问顺序,即最近访问的节点移至链表尾部,支持 LRU 缓存)。

2. 核心源码分析

(1)构造方法:初始化与顺序设置

LinkedHashMap 的构造方法继承自 HashMap,额外通过 accessOrder 字段设置顺序模式:

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {// 双向链表的头节点(最早插入/访问的节点)transient Entry<K,V> head;// 双向链表的尾节点(最晚插入/访问的节点)transient Entry<K,V> tail;// 顺序模式:false=插入顺序,true=访问顺序final boolean accessOrder;// 空参构造:默认插入顺序,使用默认容量和负载因子public LinkedHashMap() {super();accessOrder = false;}// 指定初始容量:默认插入顺序public LinkedHashMap(int initialCapacity) {super(initialCapacity);accessOrder = false;}// 指定初始容量和负载因子:默认插入顺序public LinkedHashMap(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor);accessOrder = false;}// 指定顺序模式:可设置插入顺序或访问顺序public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {super(initialCapacity, loadFactor);this.accessOrder = accessOrder;}
}
(2)顺序维护:重写 HashMap 的钩子方法

LinkedHashMap 通过重写 HashMap 的 afterNodeAccess、afterNodeInsertion、afterNodeRemoval 三个钩子方法,维护双向链表的顺序:

  1. afterNodeAccess:访问节点后调用(如 get、put 覆盖值),accessOrder 为 true 时,将当前节点移至链表尾部(更新访问顺序):
void afterNodeAccess(Node<K,V> e) {Entry<K,V> evictable;if (accessOrder && (evictable = tail) != e) {Entry<K,V> p = (Entry<K,V>)e, b = p.before, a = p.after;p.after = null;// 移除当前节点if (b == null)head = a;elseb.after = a;if (a != null)a.before = b;elseevictable = b;// 将当前节点移至尾部if (evictable == null)head = p;else {p.before = evictable;evictable.after = p;}tail = p;++modCount;}
}
  1. afterNodeInsertion:插入节点后调用,可用于删除最少使用的节点(LRU 缓存逻辑),通过 removeEldestEntry 方法判断是否删除头节点(最早访问的节点):
void afterNodeInsertion(boolean evict) {Entry<K,V> first;// evict为true且需要删除最老节点时,移除头节点if (evict && (first = head) != null && removeEldestEntry(first)) {K key = first.key;removeNode(hash(key), key, null, false, true);}
}// 可重写此方法,自定义删除最老节点的条件(如容量超过阈值)
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {return false; // 默认不删除
}
  1. afterNodeRemoval:删除节点后调用,从双向链表中移除当前节点,保证链表完整性:
void afterNodeRemoval(Node<K,V> e) {Entry<K,V> p = (Entry<K,V>)e, b = p.before, a = p.after;p.before = p.after = null;// 移除当前节点if (b == null)head = a;elseb.after = a;if (a == null)tail = b;elsea.before = b;
}
(3)遍历性能:按链表顺序遍历

LinkedHashMap 的 entrySet () 遍历依赖双向链表,直接从 head 遍历到 tail,无需遍历哈希表的空桶,遍历性能优于 HashMap:

public Set<Map.Entry<K,V>> entrySet() {Set<Map.Entry<K,V>> es;// 返回LinkedEntrySet,遍历逻辑基于双向链表return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}private class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {public Iterator<Map.Entry<K,V>> iterator() {return new LinkedEntryIterator();}// 基于双向链表的迭代器private class LinkedEntryIterator extends LinkedHashIterator implements Iterator<Map.Entry<K,V>> {public Map.Entry<K,V> next() {return nextNode(); // 从head开始,依次获取next节点}}
}

3. 性能特点

  • 增删改查:同 HashMap,无冲突时 O (1),但需额外维护双向链表,性能略低于 HashMap。
  • 遍历性能:时间复杂度 O (n),且比 HashMap 更快(无空桶遍历开销),顺序严格按插入或访问顺序。
  • 内存占用:每个节点需额外存储 prev 和 next 引用,内存开销高于 HashMap。
  • 线程安全:同 HashMap,非线程安全,多线程场景需额外同步。
  • LRU 缓存支持:设置 accessOrder=true 并重写 removeEldestEntry 方法,可实现 LRU(最近最少使用)缓存。

4. 适用场景

  • 需要保证键值对插入顺序或访问顺序的场景(如记录用户操作日志,按操作顺序存储;实现 LRU 缓存);
  • 频繁遍历键值对,对遍历性能要求高的场景;
  • 允许键为 null(仅 1 个)、值为 null 的场景。

四、TreeMap 详解与源码分析

TreeMap 是唯一支持 “键排序” 的 Map 实现类,其底层通过红黑树(自平衡二叉搜索树)实现键值对的有序存储,核心优势是 “有序存储 + 键排序”。

1. 底层数据结构

TreeMap 的底层结构为 “红黑树”,一种自平衡的二叉搜索树,具有以下特性:

  • 二叉搜索树特性:任意节点的左子树所有键小于该节点的键,右子树所有键大于该节点的键,中序遍历可得到有序键集。
  • 红黑树平衡特性:通过颜色规则(节点为红色或黑色)保证树的高度平衡,避免退化为链表,确保增删查操作时间复杂度为 O (log n)。
  • 排序方式:支持两种排序方式:
    • 自然排序:键实现 Comparable 接口,通过 compareTo () 方法比较大小(默认)。
    • 定制排序:构造 TreeMap 时传入 Comparator,通过 compare () 方法定义比较规则。
  • 节点类型:TreeMap 的 Entry 节点存储键、值、左子树、右子树、父节点及颜色信息:
static final class Entry<K,V> implements Map.Entry<K,V> {K key;V value;Entry<K,V> left;Entry<K,V> right;Entry<K,V> parent;boolean color = BLACK; // 默认黑色节点
}

2. 核心源码分析

(1)构造方法:初始化排序规则

TreeMap 的构造方法核心是指定排序规则(自然排序或定制排序),内部通过 Comparator 字段存储比较器:

public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, Serializable {// 比较器,null表示自然排序(键需实现Comparable)private final Comparator<? super K> comparator;// 红黑树的根节点private transient Entry<K,V> root;// 空参构造:默认自然排序,键需实现Comparable接口public TreeMap() {comparator = null;}// 传入Comparator:定制排序public TreeMap(Comparator<? super K> comparator) {this.comparator = comparator;}// 传入Map:按自然排序初始化public TreeMap(Map<? extends K, ? extends V> m) {comparator = null;putAll(m);}// 传入SortedMap:使用其比较器,保持排序规则一致public TreeMap(SortedMap<K, ? extends V> m) {comparator = m.comparator();try {buildFromSorted(m.size(), m.entrySet().iterator(), null, null);} catch (java.io.IOException cannotHappen) {} catch (ClassNotFoundException cannotHappen) {}}
}
(2)添加键值对:put (K key, V value)—— 排序与键唯一核心

TreeMap 的 put 方法通过红黑树的插入逻辑实现键的排序和唯一性判断,依赖比较器或 Comparable 接口:

public V put(K key, V value) {Entry<K,V> t = root;// 1. 红黑树为空,创建根节点if (t == null) {compare(key, key); // 验证键是否可比较(自然排序时键需实现Comparable)root = new Entry<>(key, value, null);size = 1;modCount++;return null;}int cmp;Entry<K,V> parent;// 2. 获取比较器(自然排序时为null)Comparator<? super K> cpr = comparator;if (cpr != null) {// 3. 定制排序:遍历红黑树,找到插入位置do {parent = t;cmp = cpr.compare(key, t.key);if (cmp < 0) // 当前键小于节点键,向左子树查找t = t.left;else if (cmp > 0) // 当前键大于节点键,向右子树查找t = t.right;else // 键相等,覆盖值并返回旧值(键唯一核心)return t.setValue(value);} while (t != null);} else {// 4. 自然排序:键需实现Comparable,否则抛出ClassCastExceptionif (key == null)throw new NullPointerException();@SuppressWarnings("unchecked")Comparable<? super K> k = (Comparable<? super K>) key;do {parent = t;cmp = k.compareTo(t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}// 5. 创建新节点,插入红黑树Entry<K,V> e = new Entry<>(key, value, parent);if (cmp < 0)parent.left = e;elseparent.right = e;// 6. 插入后修复红黑树平衡(调整颜色和旋转)fixAfterInsertion(e);size++;modCount++;return null;
}

关键逻辑:

  1. 键可比较验证:自然排序时,键必须实现 Comparable 接口,否则抛出 ClassCastException;不允许键为 null(无法比较)。
  2. 键唯一判断:通过比较器的 compare () 或 Comparable 的 compareTo () 方法判断键是否相等,返回 0 则视为相同键,覆盖值。
  3. 红黑树平衡修复:插入新节点后,通过 fixAfterInsertion 方法调整节点颜色和树的旋转(左旋转、右旋转),保证红黑树平衡。
(3)排序相关方法:NavigableMap 接口扩展

TreeMap 实现了 NavigableMap 接口,提供丰富的排序相关方法,支持键的范围查询和极值获取:

// 返回最小的键
public K firstKey() {return key(getFirstEntry());
}// 返回最大的键
public K lastKey() {return key(getLastEntry());
}// 返回小于key的最大键
public K lowerKey(K key) {return key(getLowerEntry(key));
}// 返回大于等于key的最小键
public K ceilingKey(K key) {return key(getCeilingEntry(key));
}// 返回从fromKey(含)到toKey(不含)的子Map
public SortedMap<K,V> subMap(K fromKey, K toKey) {return subMap(fromKey, true, toKey, false);
}// 返回小于toKey的所有键值对组成的子Map
public SortedMap<K,V> headMap(K toKey) {return headMap(toKey, false);
}// 返回大于等于fromKey的所有键值对组成的子Map
public SortedMap<K,V> tailMap(K fromKey) {return tailMap(fromKey, true);
}

3. 性能特点

  • 增删改查:时间复杂度均为 O (log n),红黑树的平衡操作保证了稳定的性能。
  • 遍历性能:中序遍历时间复杂度 O (n),直接得到有序键集,无需额外排序。
  • 随机访问:无索引,通过键获取值需遍历红黑树,性能低于 HashMap。
  • 内存占用:红黑树节点需存储左子树、右子树、父节点引用及颜色标记,内存开销高于 HashMap 和 LinkedHashMap。
  • 线程安全:非线程安全,多线程场景推荐使用 ConcurrentSkipListMap(线程安全的有序 Map,基于跳表实现,性能优于同步包装的 TreeMap)。

4. 适用场景

  • 需要对键进行有序存储(升序 / 降序)的场景(如按日期排序的订单数据,键为日期,值为订单列表);
  • 需要使用排序相关方法(如范围查询、获取最大 / 最小键)的场景;
  • 不允许键为 null,且键可比较(实现 Comparable 或提供 Comparator)的场景。

五、三种 Map 实现类的对比与适用场景

对比方式HashMapLinkedHashMapTreeMap
底层结构哈希表(数组 + 链表 + 红黑树)哈希表 + 双向链表红黑树(自平衡二叉搜索树)
键值对顺序无序(随机)有序(插入顺序 / 访问顺序)有序(自然排序 / 定制排序)
键唯一依据hashCode() + equals()hashCode() + equals()compareTo()/compare()
是否允许键为 null是(仅 1 个)是(仅 1 个)否(会抛 NPE)
是否允许值为 null
时间复杂度(增删改查)O (1)(无冲突);O (log n)(冲突)O (1)(无冲突,略慢);O (log n)(冲突)O(log n)
遍历性能较慢(需遍历空桶)较快(按链表顺序)中等(红黑树中序遍历,有序)
内存占用较低中等(额外存储链表引用)较高(存储树结构和颜色)
线程安全
核心优势高性能增删改查高性能 + 顺序保证(插入 / 访问)有序存储 + 键排序

适用场景选择建议

  1. HashMap:

    • 优先选择场景:无需保证键值对顺序,仅需通过键快速查找值,且频繁执行增删改查操作(如缓存用户信息、存储配置参数);
    • 避坑点:存储自定义对象作为键时,必须重写 hashCode () 和 equals ();多线程场景需注意同步。
  2. LinkedHashMap:

    • 优先选择场景:需要保证键值对插入顺序或访问顺序(如实现 LRU 缓存、记录操作日志),且频繁遍历;
    • 避坑点:内存开销高于 HashMap,不适合元素数量极大的场景;多线程场景需额外同步。
  3. TreeMap:

    • 优先选择场景:需要对键进行有序存储,或需要使用范围查询、极值获取等排序相关方法(如按时间排序的日志数据、有序字典);
    • 避坑点:键需实现 Comparable 或提供 Comparator;不支持键为 null;多线程场景推荐使用 ConcurrentSkipListMap。

六、总结

Map 接口及三大实现类是 Java 集合框架中 “键值对存储与查找” 需求的核心解决方案,其设计各有侧重:

  • HashMap:以 “高性能” 为核心,牺牲顺序,适合纯键值对查找场景,是开发中的默认首选;
  • LinkedHashMap:在 HashMap 基础上增加 “顺序保证”,平衡性能与顺序需求,支持 LRU 缓存等特殊场景;
  • TreeMap:以 “有序存储” 为核心,牺牲部分性能,适合需要键排序或范围查询的场景。

在实际开发中,还要注意线程安全的问题,但上述的三种实现类并不能保证时线程安全的,当然,在java集合体系中是有确保线程安全的集合,这里不再叙述,后续的文章可能会涉及。

http://www.dtcms.com/a/504014.html

相关文章:

  • 大连网站制作代理价格北京小程序开发价格
  • 内蒙古建设安全监督网站东道 网站建设
  • 跳格子游戏(1)
  • 谈谈你对Mysql 锁的理解
  • 网站开发有哪些模块想做分销商有什么平台
  • P14245 [CCPC 2024 Shandong I] 左移题解
  • 网站做支付宝花呗分期有哪些做家教网站
  • Altium Designer(AD24)Tools工具功能总结
  • 做分析图的地图网站自己做网站网页剧中
  • 产妇入院出院过程分享
  • Windows 安装 WSL2 全指南(2025 版)
  • StarsNote 1.0.9
  • 通信原理(007)——FFT脚本(超级实用简单)
  • 新国际网站建设wordpress对接微信
  • 广州外贸营销型网站thinkphp 网站源码
  • 电影天堂网页入口 - 免费高清电影在线观看
  • 停止线程:官方版本
  • 最好的响应式网站电子外贸网站建设
  • 有效市场假说
  • 网站图片用什么软件做网站框架
  • 农业服务网站建设方案免费的资料网站
  • 4-SpringCloud-Resilience4J服务熔断与降级
  • 网站可以叫做系统吗建站广告
  • 网站搭建说明哪家公司的网好
  • Java基础语法—分支结构
  • 郑州网站制作设计营销行网站建设
  • LeetCode 1170.比较字符串最小字母出现频次
  • 自己做的网站如何管理平台公司的定义
  • 北京网站维护浩森宇特福州网站建设案例
  • FFmpeg 基本API avcodec_open2函数内部调用流程分析