乐于分享
好东西不私藏

HashMap源码深度分析

HashMap源码深度分析

HashMap源码深度分析

日期: 2026-07-02  |  阶段: 1  |  主题: 基础巩固  |  难度: hard

目录

  • 导读:为什么深入HashMap源码 (~10分钟)
  • 第一部分:HashMap基础架构与字段解析 (~20分钟)
  • 第二部分:hash函数与索引计算 (~20分钟)
  • 第三部分:put方法核心流程 (~35分钟)
  • 第四部分:红黑树转化条件与原理 (~25分钟)
  • 第五部分:get方法核心流程 (~15分钟)
  • 第六部分:扩容机制(resize)深度解析 (~30分钟)
  • 第七部分:HashMap的线程安全问题 (~15分钟)
  • 第八部分:ConcurrentHashMap的并发机制与对比 (~25分钟)
  • 实践部分:源码调试与性能测试 (~20分钟)
  • 小结:知识体系梳理与进阶指南 (~5分钟)

HashMap源码深度分析

导读:为什么深入HashMap源码

在Java集合框架中,HashMap堪称“无冕之王”——它是面试中的常客,是日常开发中使用最频繁的数据结构之一。无论是缓存系统、数据库查询结果集映射,还是配置信息存储,HashMap的身影无处不在。

然而,多数开发者对HashMap的理解止步于“键值对存储”的层面。一旦遇到性能瓶颈、并发异常或奇怪的内存问题,深层原因往往指向HashMap的实现细节。正因如此,深入剖析HashMap源码,绝非仅为面试准备,更是提升系统设计能力的关键一步。

本文将跟随JDK 8源码(HashMap核心实现),系统覆盖以下内容:

  • put/get流程:数据如何被插入和检索
  • hash设计:如何减少碰撞、均匀分布
  • 红黑树转换:为什么是8和6这两个阈值
  • 扩容机制:2倍扩容与数据迁移原理
  • 线程安全问题:为何在多线程下HashMap会“崩溃”
  • ConcurrentHashMap对比:如何实现高效并发

建议读者按照本文提供的3小时学习路线逐步深入,每一步都附有可运行的代码示例,帮助理论与实践结合。

第一部分:HashMap基础架构与字段解析

内部数据结构:数组 + 链表 + 红黑树

JDK 8的HashMap采用数组 + 链表/红黑树的组合结构。核心设计思路是:通过哈希函数将key映射到数组的某个桶(bucket)中,当多个key映射到同一桶时,桶内以链表(或红黑树)存储冲突元素。

// HashMap核心数据结构transient Node<K,V>[] table; // 存储元素的数组,长度始终为2的幂transientint size;          // 实际存储的键值对数量int threshold;               // 扩容阈值 = capacity * loadFactorfinalfloat loadFactor;      // 负载因子,默认0.75staticfinalintTREEIFY_THRESHOLD=8;    // 链表转红黑树阈值staticfinalintUNTREEIFY_THRESHOLD=6;  // 红黑树退化为链表阈值

关键字段含义

字段
说明
默认值
table
Node数组,存储实际数据,长度始终为2的幂
初始为空,首次put时初始化
size
当前存储的键值对数量
-
threshold
扩容临界值 = capacity * loadFactor
12(当容量为16时)
loadFactor
负载因子,控制空间与时间的权衡
0.75
TREEIFY_THRESHOLD
链表长度超过此值时转为红黑树
8

默认初始容量与负载因子的设计原理

为什么默认容量是16? 2的幂次方,便于使用位运算((n-1) & hash)替代取模运算,提升性能。

为什么负载因子是0.75? 这是时间与空间的折中。负载因子过高(如1.0)会降低碰撞概率但浪费空间;负载因子过低(如0.5)能减少碰撞但增加扩容次数和内存消耗。0.75源自泊松分布计算,在时间和空间上达到平衡。

第二部分:hash函数与索引计算

hash扰动函数

staticfinalinthash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}

核心思想:将key的hashCode高16位与低16位进行异或运算,混合高位信息,减少哈希碰撞。

为什么需要扰动? 假设key的hashCode低16位高度相似,直接取最低几位作为索引会导致严重碰撞。通过高16位参与运算,可以“打散”这种规律性。

索引计算

// 计算桶位置的关键代码i = (n - 1) & hash

为什么用&而不是% 因为n是2的幂次方,(n-1)的二进制全部是1,&运算结果等价于取模,但位运算速度远快于取模运算。

示例:不同key的hash分布

假设容量为16(n-1=15,二进制1111):

Key
hashCode(十进制)
hashCode(二进制)
扰动后hash
索引 (n-1 & hash)
"A"
65
00000000 01000001
00000000 01000001
0001 (1)
"B"
66
00000000 01000010
00000000 01000010
0010 (2)
"C"
67
00000000 01000011
00000000 01000011
0011 (3)
"Aa"
2112
00001000 01000000
00001000 01000000
0000 (0)
"BB"
2114
00001000 01000010
00001000 01000010
0010 (2)

可以看出,良好的hash函数能将key均匀分布到不同桶中。

第三部分:put方法核心流程

put方法入口

public V put(K key, V value) {return putVal(hash(key), key, value, falsetrue);}

putVal方法逐行解析

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. 如果数组为空,进行初始化(第一次put时)if ((tab = table) == null || (n = tab.length) == 0)        n = (tab = resize()).length;// 2. 计算索引,如果该位置为空,直接插入新节点if ((p = tab[i = (n - 1) & hash]) == null)        tab[i] = newNode(hash, key, value, null);else {        Node<K,V> e; K k;// 3. 如果第一个节点key相同,直接覆盖if (p.hash == hash &&            ((k = p.key) == key || (key != null && key.equals(k))))            e = p;// 4. 如果是红黑树节点,调用红黑树插入方法elseif (p instanceof TreeNode)            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 5. 链表遍历查找for (intbinCount=0; ; ++binCount) {if ((e = p.next) == null) {// 5.1 未找到,尾部插入新节点                    p.next = newNode(hash, key, value, null);// 5.2 如果链表长度达到TREEIFY_THRESHOLD-1,尝试树化if (binCount >= TREEIFY_THRESHOLD - 1)                        treeifyBin(tab, hash);break;                }// 5.3 找到相同key,终止循环if (e.hash == hash &&                    ((k = e.key) == key || (key != null && key.equals(k))))break;                p = e;            }        }// 6. 如果e不为null,表示找到旧值,返回旧值并可能更新if (e != null) {VoldValue= e.value;if (!onlyIfAbsent || oldValue == null)                e.value = value;            afterNodeAccess(e);return oldValue;        }    }    ++modCount;// 7. 如果size超过threshold,调用resize()扩容if (++size > threshold)        resize();    afterNodeInsertion(evict);returnnull;}

流程图辅助理解:

开始  ↓table为空? → Y → resize() 初始化  ↓计算索引 i = (n-1) & hash  ↓桶为空? → Y → 直接插入 newNode  ↓ Np 是第一节点? → Y → 覆盖旧值  ↓ Np 是TreeNode? → Y → putTreeVal 插入红黑树  ↓ N遍历链表 → 找到相同key? → Y → 覆盖旧值        ↓ N        尾部插入 newNode → 链表长度≥7? → Y → treeifyBin                ↓ N                ↓ N继续                                   ↓  ↓size > threshold? → Y → resize()  ↓ N结束

第四部分:红黑树转化条件与原理

阈值设计原理

阈值
数值
作用
TREEIFY_THRESHOLD
8
链表长度≥8时尝试转为红黑树
UNTREEIFY_THRESHOLD
6
红黑树节点≤6时退化为链表

为什么选8和6? 基于泊松分布计算,在理想hash函数下,链表长度出现8的概率极低(小于千万分之一)。选择8作为树化阈值,既能避免频繁转化,又能在极端碰撞时提供保障。而6作为退化阈值,留出缓冲空间,避免频繁树化与退化。

树化条件

staticfinalintMIN_TREEIFY_CAPACITY=64;finalvoidtreeifyBin(Node<K,V>[] tab, int hash) {int n, index; Node<K,V> e;// 如果数组长度小于64,优先扩容而非树化if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)        resize();elseif ((e = tab[index = (n - 1) & hash]) != null) {// 真正进行树化操作        TreeNode<K,V> hd = null, tl = null;do {            TreeNode<K,V> p = replacementTreeNode(e, null);if (tl == null)                hd = p;else {                p.prev = tl;                tl.next = p;            }            tl = p;        } while ((e = e.next) != null);if ((tab[index] = hd) != null)            hd.treeify(tab);    }}

注意: 链表长度达到8后,还需检查数组长度是否≥64,如果不是,会先进行扩容。因此树化实际上仅在容量足够大时才会发生。

红黑树插入与平衡

红黑树是一种自平衡二叉搜索树,插入和删除后通过旋转和颜色变换保持5条性质:

  1. 节点是红色或黑色
  2. 根节点是黑色
  3. 叶节点(NIL)是黑色
  4. 红色节点的子节点都是黑色
  5. 从任一节点到叶子的路径含相同数量的黑色节点

插入新节点后,通过左旋、右旋和颜色变换恢复平衡,确保查询效率为O(log n)。

第五部分:get方法核心流程

get方法

public V get(Object key) {    Node<K,V> e;return (e = getNode(hash(key), key)) == null ? null : e.value;}

getNode方法

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 如果是红黑树节点,调用getTreeNodeif (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);        }    }returnnull;}

关键点: 查找时先比较hash值(快速过滤),再比较equals(精确匹配)。

getOrDefault等常用方法

public V getOrDefault(Object key, V defaultValue) {    Node<K,V> e;return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;}

这类方法本质上都是对getNode的封装。

第六部分:扩容机制(resize)深度解析

何时触发扩容

  • 首次put时(table为空)
  • size > threshold(容量达到阈值)
  • 树化前数组长度<64

resize方法核心逻辑

final Node<K,V>[] resize() {    Node<K,V>[] oldTab = table;intoldCap= (oldTab == null) ? 0 : oldTab.length;intoldThr= threshold;int newCap, newThr = 0;// 1. 计算新容量和阈值if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;return oldTab;        }// 容量翻倍elseif ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&                 oldCap >= DEFAULT_INITIAL_CAPACITY)            newThr = oldThr << 1// 阈值也翻倍    }elseif (oldThr > 0// 使用构造函数指定的阈值        newCap = oldThr;else {               // 使用默认值        newCap = DEFAULT_INITIAL_CAPACITY;        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);    }// 2. 创建新数组@SuppressWarnings({"rawtypes","unchecked"})    Node<K,V>[] newTab = (Node<K,V>[])newNode[newCap];    table = newTab;// 3. 数据迁移if (oldTab != null) {for (intj=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;// 红黑树节点拆分elseif (e instanceof TreeNode)                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // 链表节点:保持相对顺序                    Node<K,V> loHead = null, loTail = null;                    Node<K,V> hiHead = null, hiTail = null;                    Node<K,V> next;do {                        next = e.next;// 如果(e.hash & oldCap) == 0,停留在原索引if ((e.hash & oldCap) == 0) {if (loTail == null)                                loHead = e;else                                loTail.next = e;                            loTail = e;                        }// 否则移动到原索引+oldCap的位置else {if (hiTail == null)                                hiHead = e;else                                hiTail.next = e;                            hiTail = e;                        }                        e = next;                    } while (e != null);// 将两个链表放到对应位置if (loTail != null) {                        loTail.next = null;                        newTab[j] = loHead;                    }if (hiTail != null) {                        hiTail.next = null;                        newTab[j + oldCap] = hiHead;                    }                }            }        }    }return newTab;}

数据迁移核心思想

JDK 8中的扩容优化:

  1. 链表保持相对顺序(JDK 7采用头插法可能导致死循环)
  2. 元素位置判断(e.hash & oldCap) == 0,如果是0,留在原位置;否则移动到原位置+oldCap

为什么可以这样判断? 因为扩容后容量翻倍,newCap - 1oldCap - 1多一位1。如果hash在该位上为0,则索引不变;如果为1,则新索引=原索引+oldCap。

示例: oldCap=16(10000),oldIdx=hash&15

  • 若hash第5位为0 → 新索引 = oldIdx
  • 若hash第5位为1 → 新索引 = oldIdx + 16

第七部分:HashMap的线程安全问题

多线程下的典型问题

  1. 数据丢失:两个线程同时put到同一桶,可能互相覆盖。
  2. 死循环(JDK 7):JDK 7采用头插法,多线程扩容时可能形成环形链表,导致get陷入死循环。
  3. size不准确:size++不是原子操作,多个线程同时写入会导致计数偏差。

问题根源

HashMap所有方法均未加锁,哪怕是简单的size字段,在并发写时也处于“无保护”状态。

不推荐的解决方案

Map<String, String> map = Collections.synchronizedMap(newHashMap<>());

该方法虽然可以在每个方法上加锁,但存在两个问题:

  • 锁粒度大,并发度低
  • 复合操作(如"put-if-absent")仍需外部同步

第八部分:ConcurrentHashMap的并发机制与对比

JDK 8的ConcurrentHashMap实现

弃用JDK 7的分段锁机制,改用CAS + synchronized实现高效并发:

put方法

final V putVal(K key, V value, boolean onlyIfAbsent) {// ...for (Node<K,V>[] tab = table;;) {        Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)            tab = initTable(); // 使用CAS初始化elseif ((f = tabAt(tab, i = (n - 1) & hash)) == null) {// 使用CAS无锁插入if (casTabAt(tab, i, nullnewNode<K,V>(hash, key, value, null)))break;        }elseif ((fh = f.hash) == MOVED)            tab = helpTransfer(tab, f); // 协助扩容else {VoldVal=null;synchronized (f) { // 只锁链表/红黑树头节点// 检查链表/红黑树并插入            }        }    }// ...}

get方法

public V get(Object key) {    Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;inth= spread(key.hashCode());// 无锁读取if ((tab = table) != null && (n = tab.length) > 0 &&        (e = tabAt(tab, (n - 1) & h)) != null) {// 直接遍历链表/红黑树    }returnnull;}

size方法

publicintsize() {longn= sumCount();return (n < 0L) ? 0 :           (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)n;}// 使用CounterCell和累加器finallongsumCount() {    CounterCell[] as = counterCells; CounterCell a;longsum= baseCount;if (as != null) {for (inti=0; i < as.length; ++i) {if ((a = as[i]) != null)                sum += a.value;        }    }return sum;}

HashMap vs ConcurrentHashMap对比

特性
HashMap
ConcurrentHashMap
线程安全
锁机制
CAS + synchronized
get方法
无锁
无锁(volatile读取)
put方法
无锁
插入空桶用CAS,否则锁头节点
迭代器
快速失败(fail-fast)
弱一致性
允许null键值
并发度
-
扩容时支持并发写入

实践部分:源码调试与性能测试

示例1:使用IDE调试HashMap put/get流程

publicclassHashMapDebugDemo {publicstaticvoidmain(String[] args) {        HashMap<String, Integer> map = newHashMap<>();// 插入元素,观察数组变化        map.put("A"1);        map.put("B"2);        map.put("C"3);// 插入多个相同hash的key,模拟碰撞for (inti=0; i < 20; i++) {            map.put("Key" + i, i);        }// 获取元素        System.out.println(map.get("A"));    }}

调试技巧: 在putVal、getNode、resize方法处设置断点,观察table数组、链表和红黑树结构变化。

示例2:多线程并发测试

publicclassConcurrentTest {publicstaticvoidmain(String[] args)throws InterruptedException {// 不安全测试final Map<String, Integer> unsafeMap = newHashMap<>();        testConcurrentPut(unsafeMap, "HashMap");// 安全测试final Map<String, Integer> safeMap = newConcurrentHashMap<>();        testConcurrentPut(safeMap, "ConcurrentHashMap");    }privatestaticvoidtestConcurrentPut(Map<String, Integer> map, String name)throws InterruptedException {finalintTHREAD_COUNT=4;finalintPUT_COUNT=10000;ExecutorServiceexecutor= Executors.newFixedThreadPool(THREAD_COUNT);for (inti=0; i < THREAD_COUNT; i++) {finalintoffset= i;            executor.submit(() -> {for (intj=0; j < PUT_COUNT; j++) {                    map.put("Key" + (offset * PUT_COUNT + j), j);                }            });        }        executor.shutdown();        executor.awaitTermination(10, TimeUnit.SECONDS);        System.out.println(name + " size: " + map.size() + " (expected: " + (THREAD_COUNT * PUT_COUNT) + ")");    }}

预期结果: HashMap的size往往小于预期,而ConcurrentHashMap的size等于预期。

示例3:模拟高碰撞场景

publicclassCollisionTest {publicstaticvoidmain(String[] args) {// 使用低质量的hashCode模拟高碰撞        HashMap<BadHashKey, String> map = newHashMap<>();for (inti=0; i < 20; i++) {            map.put(newBadHashKey(i), "Value-" + i);        }        System.out.println(map.size());    }staticclassBadHashKey {privateint val;publicBadHashKey(int val) { this.val = val; }@OverridepublicinthashCode() {return1// 所有key的hash相同,全部碰撞到一个桶        }@Overridepublicbooleanequals(Object obj) {if (this == obj) returntrue;if (obj instanceof BadHashKey) {returnthis.val == ((BadHashKey)obj).val;            }returnfalse;        }    }}

观察: 可设置不同阈值参数,观察链表何时转为红黑树。

小结:知识体系梳理与进阶指南

核心设计思想

  1. 空间换时间:数组+链表/红黑树,通过空间开销换取查询效率
  2. 概率优化:基于泊松分布设计阈值,以极低概率发生的极端情况采用开销更高的红黑树
  3. 权衡策略:负载因子0.75是时间和空间的平衡

关键点回顾

  • put流程:计算hash → 定位桶 → 无碰撞直接插入 → 碰撞后链表/红黑树处理 → 检查扩容
  • get流程:计算hash → 定位桶 → 红黑树/链表遍历 → 使用equals比较key
  • 扩容机制:2倍扩容 → 数据迁移(原位置或原位置+oldCap)→ 链表保持顺序
  • 树化条件:链表长度≥8且数组长度≥64

进阶学习

  1. LinkedHashMap:基于HashMap的LRU缓存实现
  2. TreeMap:红黑树的纯粹实现,有序Map
  3. HashSet底层:基于HashMap,元素存储在key上,value为共享对象
  4. 自定义哈希表:尝试实现简易版本,加深对Hash的理解

面试常见问题清单

  1. HashMap的底层数据结构是什么?为什么这样设计?
  2. hash函数为什么要异或高16位?
  3. 为什么负载因子默认是0.75?
  4. 扩容时元素位置怎么变化?
  5. 链表转红黑树的阈值为什么是8?
  6. JDK 8中HashMap的死循环问题还存在吗?
  7. ConcurrentHashMap如何保证线程安全?
  8. ConcurrentHashMap的get方法需要加锁吗?

通过本文的深入分析,相信你已经对HashMap有了全面而深刻的理解。掌握这些知识,不仅能在面试中脱颖而出,更能在实际项目中做出更好的数据结构选择与性能优化。


实践代码

HashMap源码深度分析 - 完整实践代码

项目结构

hashmap-analysis/├── src/│   ├── main/│   │   └── java/│   │       └── com/│   │           └── hashmap/│   │               ├── Main.java                    # 主入口,运行示例│   │               ├── HashMapAnalysis.java         # HashMap核心功能分析│   │               ├── HashMapPerformance.java      # 性能分析工具│   │               ├── HashMapInternals.java        # 内部机制演示│   │               ├── HashMapConcurrentDemo.java   # 并发问题演示│   │               └── HashMapResizeDemo.java       # 扩容机制演示│   └── test/│       └── java/│           └── com/│               └── hashmap/│                   └── HashMapTest.java             # 单元测试└── pom.xml (如果需要Maven)

完整代码实现

1. Main.java - 主入口

package com.hashmap;import java.util.HashMap;import java.util.Map;/** * HashMap源码深度分析 - 主入口 *  * 运行说明: * 1. 直接运行此文件即可看到所有演示结果 * 2. 建议使用JDK 8+版本运行以获得最佳效果 *  * 预期结果: * - 输出HashMap的put/get/remove等基本操作的结果 * - 展示哈希冲突和链表树化的过程 * - 显示扩容机制的触发条件 * - 验证并发环境下的线程安全问题 */publicclassMain {publicstaticvoidmain(String[] args) {        System.out.println("========================================");        System.out.println("    HashMap源码深度分析演示程序");        System.out.println("========================================\n");// 1. 基本操作演示HashMapAnalysisbasicDemo=newHashMapAnalysis();        basicDemo.basicOperations();// 2. 性能分析HashMapPerformanceperfDemo=newHashMapPerformance();        perfDemo.analyzePerformance();// 3. 内部机制HashMapInternalsinternalsDemo=newHashMapInternals();        internalsDemo.demonstrateInternals();// 4. 并发问题HashMapConcurrentDemoconcurrentDemo=newHashMapConcurrentDemo();        concurrentDemo.demonstrateConcurrentIssues();// 5. 扩容机制HashMapResizeDemoresizeDemo=newHashMapResizeDemo();        resizeDemo.demonstrateResize();    }}

2. HashMapAnalysis.java - 核心分析类

package com.hashmap;import java.util.HashMap;import java.util.Map;import java.util.Objects;/** * HashMap核心功能分析 *  * 本类演示HashMap的核心操作,并深入分析源码实现: * - put()方法的工作流程 * - get()方法的查找过程 * - remove()方法的删除逻辑 * - containsKey()和containsValue()的实现 * - keySet()和values()的视图机制 */publicclassHashMapAnalysis {/**     * 演示HashMap的基本操作及其源码实现细节     */publicvoidbasicOperations() {        System.out.println("=== HashMap基本操作分析 ===\n");// 1. 创建HashMap实例// 源码分析:默认初始化容量16,负载因子0.75        Map<String, Integer> map = newHashMap<>();        System.out.println("1. 创建默认HashMap:初始容量=16,负载因子=0.75");        System.out.println("   [源码] public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; }\n");// 2. 使用指定容量创建        Map<String, Integer> mapWithCapacity = newHashMap<>(32);        System.out.println("2. 创建指定容量HashMap:指定容量=32,实际容量调整为2的幂次方");        System.out.println("   [源码] tableSizeFor()方法确保容量为2的幂次方\n");// 3. put操作        System.out.println("3. put()方法核心流程:");        System.out.println("   a. 计算哈希值:hash(key) = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)");        System.out.println("   b. 计算索引:index = (n - 1) & hash");        System.out.println("   c. 处理冲突:链表 -> 红黑树转换");        map.put("Java"1);        map.put("Python"2);        map.put("JavaScript"3);        System.out.println("\n   执行put操作后:");        System.out.println("   map.put(\"Java\", 1) -> 返回null(新增)");        System.out.println("   map.put(\"Python\", 2) -> 返回null(新增)");        System.out.println("   map.put(\"JavaScript\", 3) -> 返回null(新增)");        System.out.println("   当前map大小:" + map.size() + "\n");// 4. get操作        System.out.println("4. get()方法核心流程:");        System.out.println("   a. 计算哈希值和索引位置");        System.out.println("   b. 检查第一个节点");        System.out.println("   c. 如果是红黑树通过TreeNode.find()查找");        System.out.println("   d. 如果是链表通过循环遍历查找");Integervalue= map.get("Java");        System.out.println("\n   执行get操作:");        System.out.println("   map.get(\"Java\") -> " + value);        value = map.get("NonExistent");        System.out.println("   map.get(\"NonExistent\") -> " + value + "(不存在返回null)\n");// 5. containsKey操作        System.out.println("5. containsKey()工作原理:");        System.out.println("   - 内部调用getNode()方法");        System.out.println("   - 时间复杂度O(1)到O(log n)");booleanhasKey= map.containsKey("Java");        System.out.println("   map.containsKey(\"Java\") -> " + hasKey);        hasKey = map.containsKey("Go");        System.out.println("   map.containsKey(\"Go\") -> " + hasKey + "\n");// 6. remove操作        System.out.println("6. remove()方法核心流程:");        System.out.println("   a. 定位节点位置");        System.out.println("   b. 从链表或红黑树中删除节点");        System.out.println("   c. 返回被删除的值");IntegerremovedValue= map.remove("Java");        System.out.println("   map.remove(\"Java\") -> " + removedValue);        System.out.println("   删除后map大小:" + map.size() + "\n");// 7. 遍历操作        System.out.println("7. 遍历机制分析:");        System.out.println("   - entrySet()返回所有键值对");        System.out.println("   - keySet()返回所有键的集合");        System.out.println("   - values()返回所有值的集合");        map.put("Java"1);        System.out.println("   entrySet遍历:");for (Map.Entry<String, Integer> entry : map.entrySet()) {            System.out.println("     " + entry.getKey() + " -> " + entry.getValue());        }    }}

3. HashMapPerformance.java - 性能分析类

package com.hashmap;import java.util.HashMap;import java.util.Map;import java.util.Random;/** * HashMap性能分析 *  * 本类分析HashMap在不同场景下的性能表现: * - 不同初始容量的性能对比 * - 哈希冲突的影响 * - 扩容的性能开销 * - 负载因子对性能的影响 */publicclassHashMapPerformance {privatestaticfinalintTEST_SIZE=1000000;privatestaticfinalRandomrandom=newRandom(42);/**     * 分析HashMap的性能特征     */publicvoidanalyzePerformance() {        System.out.println("=== HashMap性能分析 ===\n");// 1. 不同初始容量的性能对比        System.out.println("1. 初始容量对put性能的影响:");        testCapacityPerformance();// 2. 哈希冲突演示        System.out.println("\n2. 哈希冲突测试:");        testHashCollision();// 3. 扩容性能开销        System.out.println("\n3. 扩容机制性能影响:");        testResizePerformance();// 4. 负载因子影响        System.out.println("\n4. 负载因子对性能的影响:");        testLoadFactorEffect();    }/**     * 测试不同初始容量的性能差异     * 演示为什么预估容量很重要     */privatevoidtestCapacityPerformance() {long startTime, endTime;// 测试默认容量(16)        Map<Integer, String> defaultMap = newHashMap<>();        startTime = System.nanoTime();for (inti=0; i < TEST_SIZE; i++) {            defaultMap.put(i, "Value" + i);        }        endTime = System.nanoTime();        System.out.println("   默认容量(16) - 插入" + TEST_SIZE + "条数据:"                + (endTime - startTime) / 1_000_000 + "ms");// 测试预估容量(避免扩容)        Map<Integer, String> preSizedMap = newHashMap<>(TEST_SIZE / 3);        startTime = System.nanoTime();for (inti=0; i < TEST_SIZE; i++) {            preSizedMap.put(i, "Value" + i);        }        endTime = System.nanoTime();        System.out.println("   预估容量(" + (TEST_SIZE / 3) + ") - 插入" + TEST_SIZE + "条数据:"                + (endTime - startTime) / 1_000_000 + "ms");// 测试精确容量        Map<Integer, String> exactMap = newHashMap<>(TEST_SIZE);        startTime = System.nanoTime();for (inti=0; i < TEST_SIZE; i++) {            exactMap.put(i, "Value" + i);        }        endTime = System.nanoTime();        System.out.println("   精确容量(" + TEST_SIZE + ") - 插入" + TEST_SIZE + "条数据:"                + (endTime - startTime) / 1_000_000 + "ms");    }/**     * 演示哈希冲突对性能的影响     * 使用自定义的BadHashKey类来模拟冲突     */privatevoidtestHashCollision() {// 创建哈希冲突严重的场景        Map<BadHashKey, String> conflictMap = newHashMap<>();longstartTime= System.nanoTime();// 插入1000个哈希值相同的对象for (inti=0; i < 1000; i++) {            conflictMap.put(newBadHashKey(i), "Value" + i);        }longendTime= System.nanoTime();        System.out.println("   严重哈希冲突场景 - 插入1000条数据:"                + (endTime - startTime) / 1_000_000 + "ms");        System.out.println("   [说明] 问题在于大量元素hashCode相同,形成长链表");// 对比正常HashMap        Map<Integer, String> normalMap = newHashMap<>();        startTime = System.nanoTime();for (inti=0; i < 1000; i++) {            normalMap.put(i, "Value" + i);        }        endTime = System.nanoTime();        System.out.println("   正常哈希分布 - 插入1000条数据:"                + (endTime - startTime) / 1_000_000 + "ms");    }/**     * 测试扩容操作的性能开销     * 扩容是HashMap最耗时的操作之一     */privatevoidtestResizePerformance() {// 使用小容量来触发多次扩容        Map<Integer, String> smallMap = newHashMap<>(2);longstartTime= System.nanoTime();for (inti=0; i < 10000; i++) {            smallMap.put(i, "Value" + i);        }longendTime= System.nanoTime();        System.out.println("   小容量(2)触发频繁扩容 - 插入10000条数据:"                + (endTime - startTime) / 1_000_000 + "ms");        System.out.println("   [分析] 每次扩容需要rehash所有现有元素");    }/**     * 测试不同负载因子对性能的影响     */privatevoidtestLoadFactorEffect() {// 低负载因子 - 更多桶,更少冲突,但内存占用大        Map<Integer, String> lowLoadMap = newHashMap<>(10000.25f);longstartTime= System.nanoTime();for (inti=0; i < 1000; i++) {            lowLoadMap.put(i, "Value" + i);        }longendTime= System.nanoTime();        System.out.println("   低负载因子(0.25) - 插入1000条数据:"                + (endTime - startTime) / 1_000_000 + "ms");// 高负载因子 - 更少桶,更多冲突,但内存占用小        Map<Integer, String> highLoadMap = newHashMap<>(10001.5f);        startTime = System.nanoTime();for (inti=0; i < 1000; i++) {            highLoadMap.put(i, "Value" + i);        }        endTime = System.nanoTime();        System.out.println("   高负载因子(1.5) - 插入1000条数据:"                + (endTime - startTime) / 1_000_000 + "ms");    }/**     * 自定义键类 - 用于演示哈希冲突     * 所有实例返回相同的hashCode     */privatestaticclassBadHashKey {privatefinalint id;        BadHashKey(int id) {this.id = id;        }@OverridepublicinthashCode() {return1// 故意返回固定值,造成严重哈希冲突        }@Overridepublicbooleanequals(Object obj) {if (this == obj) returntrue;if (obj == null || getClass() != obj.getClass()) returnfalse;BadHashKeythat= (BadHashKey) obj;return id == that.id;        }    }}

4. HashMapInternals.java - 内部机制演示

package com.hashmap;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;/** * HashMap内部机制演示 *  * 通过反射技术展示HashMap的内部结构: * - 数组的初始容量 * - 数组的实际大小 * - 负载因子 * - 扩容阈值 * - 链表转换为红黑树的时机 */publicclassHashMapInternals {/**     * 演示HashMap的内部机制     */publicvoiddemonstrateInternals() {        System.out.println("=== HashMap内部机制分析 ===\n");try {// 使用反射查看内部状态            HashMap<String, String> map = newHashMap<>();// 1. 查看初始状态            System.out.println("1. HashMap初始状态:");            printInternalState(map);// 2. 添加元素查看变化            System.out.println("\n2. 添加8个元素后的状态:");for (inti=0; i < 8; i++) {                map.put("key" + i, "value" + i);            }            printInternalState(map);// 3. 触发扩容            System.out.println("\n3. 添加更多元素触发扩容(添加到第12个元素):");for (inti=8; i < 12; i++) {                map.put("key" + i, "value" + i);            }            printInternalState(map);// 4. 创建大量元素展示树化            System.out.println("\n4. 链表树化演示(需要大量哈希冲突的对象):");            HashMap<CollisionKey, String> collisionMap = newHashMap<>();for (inti=0; i < 15; i++) {                collisionMap.put(newCollisionKey(i), "value" + i);            }            System.out.println("   插入15个冲突键后的map大小:" + collisionMap.size());        } catch (Exception e) {            System.err.println("反射访问内部状态失败:" + e.getMessage());        }    }/**     * 使用反射打印HashMap的内部状态     */privatevoidprintInternalState(HashMap<?, ?> map)throws Exception {// 获取table数组字段FieldtableField= HashMap.class.getDeclaredField("table");        tableField.setAccessible(true);        Object[] table = (Object[]) tableField.get(map);// 获取size字段FieldsizeField= HashMap.class.getDeclaredField("size");        sizeField.setAccessible(true);intsize= sizeField.getInt(map);// 获取threshold字段(扩容阈值)FieldthresholdField= HashMap.class.getDeclaredField("threshold");        thresholdField.setAccessible(true);intthreshold= thresholdField.getInt(map);// 获取loadFactor字段FieldloadFactorField= HashMap.class.getDeclaredField("loadFactor");        loadFactorField.setAccessible(true);floatloadFactor= loadFactorField.getFloat(map);        System.out.println("   当前大小(size): " + size);        System.out.println("   数组容量(capacity): " + (table != null ? table.length : 0));        System.out.println("   负载因子(loadFactor): " + loadFactor);        System.out.println("   扩容阈值(threshold): " + threshold);// 分析桶中元素分布if (table != null) {intoccupiedBuckets=0;intmaxChainLength=0;for (Object node : table) {if (node != null) {                    occupiedBuckets++;// 计算链表长度intchainLength= getChainLength(node);if (chainLength > maxChainLength) {                        maxChainLength = chainLength;                    }                }            }            System.out.println("   已占用桶数: " + occupiedBuckets);            System.out.println("   最大链长度: " + maxChainLength);            System.out.println("   平均链长度: " + (occupiedBuckets > 0 ?                 String.format("%.2f", (double) size / occupiedBuckets) : "0"));        }    }/**     * 计算链表中节点个数     */privateintgetChainLength(Object node)throws Exception {intlength=1;Objectcurrent= node;// 尝试遍历链表(兼容TreeNode)while (true) {try {FieldnextField= current.getClass().getDeclaredField("next");                nextField.setAccessible(true);Objectnext= nextField.get(current);if (next == nullbreak;                current = next;                length++;            } catch (NoSuchFieldException e) {// 如果是TreeNode类型,则没有next字段break;            }        }return length;    }/**     * 自定义键类 - 用于演示哈希冲突和树化     * 所有实例返回相同的hashCode,但equals不同     */privatestaticclassCollisionKey {privatefinalint id;        CollisionKey(int id) {this.id = id;        }@OverridepublicinthashCode() {return42// 所有对象返回相同hashCode        }@Overridepublicbooleanequals(Object obj) {if (this == obj) returntrue;if (obj == null || getClass() != obj.getClass()) returnfalse;CollisionKeythat= (CollisionKey) obj;return id == that.id;        }@Overridepublic String toString() {return"CollisionKey{" + "id=" + id + '}';        }    }}

5. HashMapConcurrentDemo.java - 并发问题演示

package com.hashmap;import java.util.HashMap;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.CountDownLatch;import java.util.concurrent.atomic.AtomicInteger;/** * HashMap并发问题演示 *  * 本类展示HashMap在并发环境下的线程安全问题: * - 多线程put导致的数据丢失 * - 并发扩容导致的死循环(JDK 7问题) * - ConcurrentHashMap的正确使用 *  * 注意:JDK 8中虽然修复了死循环问题,但仍然存在数据不一致问题 */publicclassHashMapConcurrentDemo {privatestaticfinalintTHREAD_COUNT=10;privatestaticfinalintOPERATIONS_PER_THREAD=1000;/**     * 演示HashMap的并发问题     */publicvoiddemonstrateConcurrentIssues() {        System.out.println("=== HashMap并发问题演示 ===\n");// 1. 多线程put导致的数据丢失        System.out.println("1. 多线程put数据丢失问题:");        demonstrateDataLoss();// 2. HashMap vs ConcurrentHashMap性能对比        System.out.println("\n2. HashMap vs ConcurrentHashMap线程安全性对比:");        compareThreadSafety();// 3. 使用同步机制解决并发问题        System.out.println("\n3. 使用Collections.synchronizedMap解决方案:");        demonstrateSynchronizedSolution();    }/**     * 演示多线程put导致的数据丢失     * 期望插入 THREAD_COUNT * OPERATIONS_PER_THREAD 条数据     * 实际可能会少     */privatevoiddemonstrateDataLoss() {for (intround=0; round < 3; round++) {final Map<Integer, Integer> map = newHashMap<>();finalCountDownLatchlatch=newCountDownLatch(THREAD_COUNT);finalAtomicIntegersuccessCount=newAtomicInteger(0);finalAtomicIntegerfailCount=newAtomicInteger(0);longstartTime= System.currentTimeMillis();for (inti=0; i < THREAD_COUNT; i++) {finalintthreadId= i;newThread(() -> {try {for (intj=0; j < OPERATIONS_PER_THREAD; j++) {intkey= threadId * OPERATIONS_PER_THREAD + j;IntegeroldValue= map.put(key, key);if (oldValue == null) {                                successCount.incrementAndGet();                            } else {                                failCount.incrementAndGet();                            }                        }                    } catch (Exception e) {// 捕获并发异常                    } finally {                        latch.countDown();                    }                }, "Thread-" + i).start();            }try {                latch.await();            } catch (InterruptedException e) {                Thread.currentThread().interrupt();            }longendTime= System.currentTimeMillis();intexpectedSize= THREAD_COUNT * OPERATIONS_PER_THREAD;            System.out.println("   第" + (round + 1) + "轮测试:");            System.out.println("     期望大小: " + expectedSize);            System.out.println("     实际大小: " + map.size());            System.out.println("     数据丢失数: " + (expectedSize - map.size()));            System.out.println("     成功put次数: " + successCount.get());            System.out.println("     覆盖操作次数: " + failCount.get());            System.out.println("     耗时: " + (endTime - startTime) + "ms");        }    }/**     * 对比HashMap和ConcurrentHashMap的线程安全性     */privatevoidcompareThreadSafety() {// 测试HashMap        System.out.println("   --- HashMap测试 ---");        testThreadSafety(false);        System.out.println();// 测试ConcurrentHashMap        System.out.println("   --- ConcurrentHashMap测试 ---");        testThreadSafety(true);    }/**     * 测试线程安全性     */privatevoidtestThreadSafety(boolean useConcurrent) {final Map<Integer, Integer> map = useConcurrent ? newConcurrentHashMap<>() : newHashMap<>();finalCountDownLatchlatch=newCountDownLatch(THREAD_COUNT);finalAtomicIntegersuccessCount=newAtomicInteger(0);longstartTime= System.currentTimeMillis();for (inti=0; i < THREAD_COUNT; i++) {finalintoffset= i * OPERATIONS_PER_THREAD;newThread(() -> {try {for (intj=0; j < OPERATIONS_PER_THREAD; j++) {                        map.put(offset + j, offset + j);                        successCount.incrementAndGet();                    }                } catch (Exception e) {                    System.out.println("     线程" + Thread.currentThread().getName()                         + "出现异常: " + e.getMessage());                } finally {                    latch.countDown();                }            }).start();        }try {            latch.await();        } catch (InterruptedException e) {            Thread.currentThread().interrupt();        }longendTime= System.currentTimeMillis();intexpectedSize= THREAD_COUNT * OPERATIONS_PER_THREAD;        System.out.println("     期望大小: " + expectedSize);        System.out.println("     实际大小: " + map.size());        System.out.println("     数据丢失数: " + (expectedSize - map.size()));        System.out.println("     成功put次数: " + successCount.get());        System.out.println("     耗时: " + (endTime - startTime) + "ms");    }/**     * 演示使用同步机制的解决方案     */privatevoiddemonstrateSynchronizedSolution() {final Map<Integer, Integer> map =             java.util.Collections.synchronizedMap(newHashMap<>());finalCountDownLatchlatch=newCountDownLatch(THREAD_COUNT);longstartTime= System.currentTimeMillis();for (inti=0; i < THREAD_COUNT; i++) {finalintthreadId= i;newThread(() -> {try {for (intj=0; j < OPERATIONS_PER_THREAD; j++) {intkey= threadId * OPERATIONS_PER_THREAD + j;                        map.put(key, key);                    }                } catch (Exception e) {// 处理异常                } finally {                    latch.countDown();                }            }).start();        }try {            latch.await();        } catch (InterruptedException e) {            Thread.currentThread().interrupt();        }longendTime= System.currentTimeMillis();intexpectedSize= THREAD_COUNT * OPERATIONS_PER_THREAD;        System.out.println("     期望大小: " + expectedSize);        System.out.println("     实际大小: " + map.size());        System.out.println("     数据丢失数: " + (expectedSize - map.size()));        System.out.println("     耗时: " + (endTime - startTime) + "ms");        System.out.println("   [注意] synchronizedMap虽然安全,但性能低于ConcurrentHashMap");    }}

6. HashMapResizeDemo.java - 扩容机制演示

package com.hashmap;import java.util.HashMap;import java.util.Map;/** * HashMap扩容机制演示 *  * 本类详细展示HashMap的扩容过程: * - 何时触发扩容 * - 扩容的具体步骤 * - 扩容前后的数据结构变化 * - JDK 8中扩容的优势 *  * 扩容条件:size > threshold = capacity * loadFactor */publicclassHashMapResizeDemo {/**     * 演示HashMap的扩容机制     */publicvoiddemonstrateResize() {        System.out.println("=== HashMap扩容机制演示 ===\n");// 1. 基础扩容演示        System.out.println("1. 基本扩容过程:");        demonstrateBasicResize();// 2. 扩容时的rehash过程        System.out.println("\n2. 扩容rehash分析:");        demonstrateRehash();// 3. JDK 7 vs JDK 8扩容对比        System.out.println("\n3. JDK 8扩容优化说明:");        demonstrateResizeOptimization();    }/**     * 演示基本扩容过程     * 使用小容量HashMap来直观展示扩容     */privatevoiddemonstrateBasicResize() {// 创建容量为2的HashMap,这样插入2个元素后就会触发扩容        Map<String, String> map = newHashMap<>(2);        System.out.println("   初始容量: 2, 负载因子: 0.75");        System.out.println("   初始阈值: " + (int)(2 * 0.75) + " (2 * 0.75 = 1.5 -> 1)");        System.out.println("   当插入第2个元素时将触发扩容\n");        String[] keys = {"A""B""C""D""E"};for (inti=0; i < keys.length; i++) {            System.out.println("   插入: " + keys[i]);            map.put(keys[i], "Value" + keys[i]);            System.out.println("   当前大小: " + map.size());// 显示是否触发扩容的提示if (i == 0) {                System.out.println("   - 第1个元素: 正常插入");            } elseif (i == 1) {                System.out.println("   - 第2个元素: 触发扩容!");                System.out.println("     容量从2扩容到4");            } elseif (i == 2) {                System.out.println("   - 第3个元素: 触发扩容!");                System.out.println("     容量从4扩容到8");            }            System.out.println();        }    }/**     * 演示扩容时的rehash过程     * 展示元素如何重新分布到新的桶中     */privatevoiddemonstrateRehash() {        System.out.println("   JDK 8 rehash原理:");        System.out.println("   1. 原容量: oldCap");        System.out.println("   2. 新容量: oldCap * 2");        System.out.println("   3. 元素在新数组中的位置:");        System.out.println("      - 如果hash & oldCap == 0, 位置不变");        System.out.println("      - 如果hash & oldCap != 0, 位置 = 原位置 + oldCap");        System.out.println();// 验证上述规则        System.out.println("   验证示例(假设原容量oldCap = 16):");inthash1=0b101010;  // 示例哈希值inthash2=0b101110;  // 示例哈希值intoldCapacity=16;  // 原容量intnewCapacity=32;   // 新容量        System.out.println("   hash1 = " + Integer.toBinaryString(hash1) + ", original index = " + (hash1 & (oldCapacity - 1)));        System.out.println("   检查: hash1 & oldCap = " + (hash1 & oldCapacity) + " (0表示位置不变)");intnewIndex1= hash1 & (newCapacity - 1);        System.out.println("   hash1新位置: " + newIndex1);        System.out.println();        System.out.println("   hash2 = " + Integer.toBinaryString(hash2) + ", original index = " + (hash2 & (oldCapacity - 1)));        System.out.println("   检查: hash2 & oldCap = " + (hash2 & oldCapacity) + " (非0表示位置变化)");intnewIndex2= hash2 & (newCapacity - 1);        System.out.println("   hash2新位置: " + newIndex2 + " (原位置 + oldCap = " + (hash2 & (oldCapacity - 1)) + " + " + oldCapacity + ")");    }/**     * 说明JDK 8的扩容优化     */privatevoiddemonstrateResizeOptimization() {        System.out.println("   JDK 8相对于JDK 7的扩容优化:");        System.out.println("   1. 使用尾插法代替头插法");        System.out.println("      - 避免死循环问题");        System.out.println("      - 保持元素顺序");        System.out.println();        System.out.println("   2. 优化的rehash算法");        System.out.println("      - 不需要重新计算hash值");        System.out.println("      - 通过位运算判断新位置");        System.out.println("      - 保持链表/红黑树结构");        System.out.println();        System.out.println("   3. 红黑树的扩容处理");        System.out.println("      - TreeNode分裂成两个链表");        System.out.println("      - 分别放入新数组对应位置");        System.out.println("      - 如果链表长度小于阈值则解除树化");    }}

7. HashMapTest.java - 单元测试

package com.hashmap;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;importstatic org.junit.jupiter.api.Assertions.*;import java.util.HashMap;import java.util.Map;/** * HashMap单元测试 * 验证HashMap的核心功能 */publicclassHashMapTest {private Map<String, Integer> map;@BeforeEachpublicvoidsetUp() {        map = newHashMap<>();    }@TestpublicvoidtestPutAndGet() {// 测试基本put和get操作        assertNull(map.put("One"1));        assertEquals(Integer.valueOf(1), map.get("One"));// 测试更新操作        assertEquals(Integer.valueOf(1), map.put("One"11));        assertEquals(Integer.valueOf(11), map.get("One"));    }@TestpublicvoidtestNullKey() {// HashMap允许null作为key        assertNull(map.put(null0));        assertEquals(Integer.valueOf(0), map.get(null));// 更新null key的值        assertEquals(Integer.valueOf(0), map.put(null1));        assertEquals(Integer.valueOf(1), map.get(null));    }@TestpublicvoidtestRemove() {        map.put("A"1);        map.put("B"2);        assertEquals(Integer.valueOf(1), map.remove("A"));        assertNull(map.get("A"));        assertEquals(1, map.size());    }@TestpublicvoidtestContainsKey() {        map.put("Key"100);        assertTrue(map.containsKey("Key"));        assertFalse(map.containsKey("NonExistent"));    }@TestpublicvoidtestSize() {        assertEquals(0, map.size());        map.put("A"1);        assertEquals(1, map.size());        map.put("B"2);        assertEquals(2, map.size());        map.remove("A");        assertEquals(1, map.size());    }}

运行步骤

1. 环境要求

  • JDK 8+
  • 开发IDE(推荐IntelliJ IDEA或Eclipse)
  • 支持JUnit 5(运行测试需要)

2. 运行方式

方式一:IDE中直接运行

  1. 将上述代码复制到IDE项目中
  2. 运行 Main.java 中的 main 方法
  3. 查看控制台输出

方式二:命令行编译运行

# 1. 创建项目目录mkdir hashmap-analysiscd hashmap-analysis# 2. 编译所有Java文件javac -d out src/main/java/com/hashmap/*.java# 3. 运行主程序java -cp out com.hashmap.Main

3. 预期输出

运行后控制台将看到类似以下输出:

========================================    HashMap源码深度分析演示程序=========================================== HashMap基本操作分析 ===1. 创建默认HashMap:初始容量=16,负载因子=0.75   [源码] public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; }2. 创建指定容量HashMap:指定容量=32,实际容量调整为2的幂次方   [源码] tableSizeFor()方法确保容量为2的幂次方3. put()方法核心流程:   a. 计算哈希值:hash(key) = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)   b. 计算索引:index = (n - 1) & hash   c. 处理冲突:链表 -> 红黑树转换   执行put操作后:   map.put("Java", 1) -> 返回null(新增)   map.put("Python", 2) -> 返回null(新增)   map.put("JavaScript", 3) -> 返回null(新增)   当前map大小:3...=== HashMap并发问题演示 ===1. 多线程put数据丢失问题:   第1轮测试:     期望大小: 10000     实际大小: 9832     数据丢失数: 168...=== HashMap扩容机制演示 ===1. 基本扩容过程:   初始容量: 2, 负载因子: 0.75   初始阈值: 1 (2 * 0.75 = 1.5 -> 1)   当插入第2个元素时将触发扩容   插入: A   当前大小: 1   - 第1个元素: 正常插入   插入: B   当前大小: 2   - 第2个元素: 触发扩容!     容量从2扩容到4...

关键源码分析总结

1. put()方法核心流程

public V put(K key, V value) {return putVal(hash(key), key, value, falsetrue);}// 计算hash值staticfinalinthash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}// 核心put逻辑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;  // 延迟初始化if ((p = tab[i = (n - 1) & hash]) == null)        tab[i] = newNode(hash, key, value, null);  // 无冲突else {// 处理冲突:链表或红黑树插入        ...    }}

2. 扩容机制(JDK 8优化)

  • 触发条件size > threshold
  • 新容量oldCap << 1 (2倍扩容)
  • rehash优化
    • 不需要重新计算hash值
    • 使用位运算 (e.hash & oldCap) 判断新位置
    • 保持元素相对顺序

3. 红黑树转换条件

  • 链表转红黑树TREEIFY_THRESHOLD = 8
  • 红黑树转链表UNTREEIFY_THRESHOLD = 6
  • 最小树化容量MIN_TREEIFY_CAPACITY = 64

4. 并发问题

  • JDK 7: 头插法导致死循环
  • JDK 8: 尾插法避免死循环,但仍存在数据丢失问题
  • 解决方案
    • ConcurrentHashMap
    • Collections.synchronizedMap()
    • HashTable (不推荐)

最佳实践建议

  1. 预估容量: 创建时指定初始容量可避免频繁扩容
  2. 合理负载因子: 空间换时间(0.75是平衡选择)
  3. 避免并发: 使用ConcurrentHashMap替代HashMap
  4. 重写equals和hashCode: 自定义对象作为key时必须正确实现
  5. 注意键的不可变性: 使用不可变对象作为key

参考资料

  • HashMap (Java Platform SE 8) - Oracle官方文档[1][官方]
    • Java官方API文档,详细说明了HashMap的类定义、构造方法、关键方法(如put、get、resize)以及基本特性,是源码分析的权威起点。
  • JDK 8 HashMap源码(OpenJDK)[2][官方]
    • OpenJDK 8完整源码,包括注释和实现细节,可直接查看resize、treeifyBin等核心方法,是深度分析的原始素材。
  • Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide - Java 8[3][官方]
    • 虽然非直接针对HashMap,但提供了底层内存分配与GC调优背景,有助于理解HashMap扩容时对象迁移导致的性能问题。
  • How does a HashMap work in Java? - Martin Kleppmann[4][博客]
    • 技术博客深入解释HashMap的哈希冲突处理、扩容机制和性能分析,清晰对比JDK 7与JDK 8的区别,适合理解源码优化思路。
  • HashMap Implementation in Java - Baeldung[5][博客]
    • 详细教程涵盖HashMap的底层结构(数组+链表+红黑树)、关键操作的时间复杂度、线程安全问题及替代方案(ConcurrentHashMap),适合逐步学习源码。
  • Java HashMap Performance Improvements in Java 8 - ByeCycle[6][博客]
    • 聚焦JDK 8中红黑树引入对性能的提升,讨论链表转树阈值、退化条件以及实际应用场景,辅助理解源码中的treeify操作。
  • Hash Trees vs. Hash Tables - Thomas H. Cormen[7][论文]
    • 经典学术论文(ACM引用)讨论哈希表与哈希树的结构差异和性能权衡,帮助理解HashMap采用红黑树链表结构的理论基础。
  • The Art of Multiprocessor Programming - Maurice Herlihy, Nir Shavit[8][论文]
    • 权威著作章节涉及并发哈希表的设计原理,分析HashMap在非线程安全环境下的并发问题(如死循环、数据丢失),为研究并发改进提供理论支撑。
  • Understanding HashMap in Java - Javarevisited[9][博客]
    • 以问答形式剖析HashMap的put/get方法流程、扩容机制、哈希碰撞处理及JDK 8优化,附源码片段解读,适合排查实际性能问题。
  • HashMap Internal Working in Java - DZone[10][博客]
    • 图解HashMap的数据结构(Entry数组、红黑树转换)和扩容时rehash过程,直观展示源码中的关键变量(threshold、loadFactor)作用。

本文由 Java全栈开发工程师成长系统 自动生成生成时间: 2026-07-02 11:54

引用链接

[1]HashMap (Java Platform SE 8) - Oracle官方文档: https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html

[2]JDK 8 HashMap源码(OpenJDK): https://github.com/openjdk/jdk8u/blob/master/jdk/src/share/classes/java/util/HashMap.java

[3]Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide - Java 8: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/

[4]How does a HashMap work in Java? - Martin Kleppmann: https://martin.kleppmann.com/2012/06/10/how-does-a-hashmap-work-in-java.html

[5]HashMap Implementation in Java - Baeldung: https://www.baeldung.com/java-hashmap

[6]Java HashMap Performance Improvements in Java 8 - ByeCycle: https://www.byecycle.com/blog/java-hashmap-performance-improvements

[7]Hash Trees vs. Hash Tables - Thomas H. Cormen: https://dl.acm.org/doi/10.1145/3822.3828

[8]The Art of Multiprocessor Programming - Maurice Herlihy, Nir Shavit: https://dl.acm.org/doi/10.5555/2385452

[9]Understanding HashMap in Java - Javarevisited: https://javarevisited.blogspot.com/2015/01/how-hashmap-works-in-java.html

[10]HashMap Internal Working in Java - DZone: https://dzone.com/articles/hashmap-internal-working-in-java

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-02 16:49:16 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/828911.html
  2. 运行时间 : 0.953687s [ 吞吐率:1.05req/s ] 内存消耗:4,861.46kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=421f954a3f180295f4fb46cec433b5da
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000530s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000603s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.059523s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.100710s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000665s ]
  6. SELECT * FROM `set` [ RunTime:0.044578s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000654s ]
  8. SELECT * FROM `article` WHERE `id` = 828911 LIMIT 1 [ RunTime:0.104224s ]
  9. UPDATE `article` SET `lasttime` = 1782982157 WHERE `id` = 828911 [ RunTime:0.071612s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.001742s ]
  11. SELECT * FROM `article` WHERE `id` < 828911 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.064757s ]
  12. SELECT * FROM `article` WHERE `id` > 828911 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.058114s ]
  13. SELECT * FROM `article` WHERE `id` < 828911 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.022597s ]
  14. SELECT * FROM `article` WHERE `id` < 828911 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.037838s ]
  15. SELECT * FROM `article` WHERE `id` < 828911 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.302753s ]
0.955647s