杠精派
派聪明
0/512

热门评论

嘿嘿 2026年08月29日 14:17
引用原文: Concurrent Modification Exception。
@派聪明 这个是什么异常
点赞
回复1 取消回复
派聪明 2026年08月29日 14:17
**ConcurrentModificationException(并发修改异常)** 是 Java集合框架中的一种错误检测机制(fail-fast 快速失败)抛出的异常。 **产生场景**:在使用迭代器遍历集合的过程中,集合的结构被修改(添加、删除元素等)时抛出。 **原理**:迭代器遍历时会记录一个 `expectedModCount`值,集合每次被修改(add/remove 等),`modCount` 就会加1。迭代器在执行 `hashNext()/next()` 时会检查: ```javaif (modCount != expectedModCount) throw new ConcurrentModificationException(); ``` **常见触发例子**:在 for-each循环(本质是迭代器)中直接调用 `list.remove()`修改集合。 **解决方案**: 1. 使用迭代器自带的 `iterator.remove()`删除元素; 2. 使用 `removeIf()` 方法; 3. 多线程环境下使用 `java.util.concurrent` 包下的 fail-safe容器,如 `CopyOnWriteArrayList`,它在遍历时操作的是原集合的拷贝,不会抛出该异常。 **注意**:这个异常只建议用于检测 bug,不应依赖它来做并发控制逻辑,因为 modCount恰好相等时异常可能不会抛出。
点赞
回复 取消回复

9 条评论

嘿嘿 2026年09月02日 13:45
引用原文: (e.hash & oldCap) == 0 时,
@派聪明 这个怎么描述
点赞
回复1 取消回复
派聪明 2026年09月02日 13:46
这是 **JDK8 中 HashMap扩容时判断节点位置**的条件,完整写法是 `(e.hash & oldCap) ==0`。 **可以这样描述:** HashMap扩容时(容量翻倍,如16 →32),并不需要重新计算每个节点的哈希值,而是用该条件判断节点的新位置: - **`(e.hash & oldCap) ==0`**:扩容后该节点**保留在原索引位置**不变; - **`(e.hash & oldCap) !=0`**:该节点需要**移动到「原索引 +旧数组容量」的新位置**(例如原索引5,旧容量16,则新位置为5 +16 =21)。 **原理:** 由于数组长度始终是2 的幂次方,扩容后容量翻倍,索引计算从 `hash & (n-1)`变为 `hash & (2n-1)`,两者的区别只在于二进制中新增的那一位高位。而 `oldCap`(如16 的二进制 `10000`)正好只有这一位是1,所以 `hash & oldCap` 就是检查哈希值在这一位上是0 还是1,从而快速确定节点去留。 **优点:**避免了对所有元素重新计算哈希和取模,只需一次位运算,大幅提升扩容性能。
点赞
回复 取消回复
嘿嘿 2026年08月29日 14:43
引用原文:HashMap 是通过 hash & (n-1) 来定位元素下标的,n 为数组的大小,也就是 HashMap 底层数组的容量。 数组长度-1 正好相当于一个“低位掩码”——掩码的低位最好全是 1,这样 & 运算才有意义,否则结果一定是 0。
@派聪明 默认不是10吗减1就是9怎么一个第为掩码
点赞
回复1 取消回复
派聪明 2026年08月29日 14:43
这里有个误解:**HashMap 的默认初始容量不是10,而是16**。 源码中定义: ```javastatic final int DEFAULT_INITIAL_CAPACITY =1 <<4; //16``` 而且 HashMap 的容量**永远是2 的幂次方**。即使你构造时传17,它也会通过 `tableSizeFor()`调整为32。 **为什么“低位掩码”成立?** 正因为容量是2 的幂次方,n-1 的二进制才是一个“低位全1”的形式。以默认容量16 为例: -16 的二进制:`00010000` -16-1 =15 的二进制:`00001111` 用 hash 和15做与运算: ``` 101001011100010000100101 (hash) &000000000000000000001111 (n-1 =15) ---------------------------------- 000000000000000000000101 (结果 =5) ``` 高位全部被0 清零,只保留低4 位,结果范围正好是0~15,落在数组下标范围内。而且当 n 是2 的幂时,`hash & (n-1)`等价于 `hash % n`,但位运算比取模快得多。 **如果容量是10呢?** -10-1 =9 的二进制是 `1001`,低位不是全1。 比如 hash =6(二进制 `0110`):`0110 &1001 =0000`,结果是0; hash =15(`1111`):`1111 &1001 =1001`,结果是9。 这样会有很多下标(如2、4、5、6 等)永远取不到,哈希分布严重不均匀。所以 HashMap才强制容量为2 的幂次方,保证 n-1 是低位全1 的掩码,让 hash 的每一位都能参与运算,元素分布均匀。
点赞
回复 取消回复
嘿嘿 2026年08月29日 14:36
引用原文:哈希表的索引是通过 h & (n-1) 计算的,n 是底层数组的容量;n-1 和某个哈希值做 & 运算,相当于截取了最低的四位。如果数组的容量很小,只取 h 的低位很容易导致哈希冲突。
@派聪明 与运算是怎么计算的
点赞
回复1 取消回复
派聪明 2026年08月29日 14:37
# &(与)运算的计算方法##基本规则`&` 是**按位与**运算:两个二进制位**都为1 时结果才是1**,否则为0。 | 位 a | 位 b | a & b | |------|------|-------| |0 |0 |0 | |0 |1 |0 | |1 |0 |0 | |1 |1 |1 | ##计算示例比如5 &3: ``` 0101 (5 的二进制) &0011 (3 的二进制) ------ 0001 (结果 =1) ``` 逐位比较:最高位0&0=0,第二位1&0=0,第三位0&1=0,最后一位1&1=1,结果就是 `0001`,即十进制1。 ## 在 HashMap中的应用假设数组长度 n =16,则 n-1 =15,二进制是 `00001111`(低位4 个1)。 ``` 101001011100010000100101 (哈希值 h) &000000000000000000001111 (n-1 =15) --------------------------------000000000000000000000101 (结果 =5) ``` 因为 n-1的高位全是0,所以 h的高位全部被“清零”,只保留了最低4 位 `0101`(十进制5),这就是“截取低位”的效果。 **为什么容易冲突?** 高位不同、但低4 位相同的两个哈希值(比如 `...01111000` 和 `...11101000`,低4 位都是1000),计算出的索引都一样,就发生了哈希冲突。这也是 HashMap 的 hash函数要做 `h ^ (h >>>16)` 的原因——把高位信息混入低位,增加随机性,减少冲突。
点赞
回复 取消回复
嘿嘿 2026年08月29日 14:17
引用原文: Concurrent Modification Exception。
@派聪明 这个是什么异常
点赞
回复1 取消回复
派聪明 2026年08月29日 14:17
**ConcurrentModificationException(并发修改异常)** 是 Java集合框架中的一种错误检测机制(fail-fast 快速失败)抛出的异常。 **产生场景**:在使用迭代器遍历集合的过程中,集合的结构被修改(添加、删除元素等)时抛出。 **原理**:迭代器遍历时会记录一个 `expectedModCount`值,集合每次被修改(add/remove 等),`modCount` 就会加1。迭代器在执行 `hashNext()/next()` 时会检查: ```javaif (modCount != expectedModCount) throw new ConcurrentModificationException(); ``` **常见触发例子**:在 for-each循环(本质是迭代器)中直接调用 `list.remove()`修改集合。 **解决方案**: 1. 使用迭代器自带的 `iterator.remove()`删除元素; 2. 使用 `removeIf()` 方法; 3. 多线程环境下使用 `java.util.concurrent` 包下的 fail-safe容器,如 `CopyOnWriteArrayList`,它在遍历时操作的是原集合的拷贝,不会抛出该异常。 **注意**:这个异常只建议用于检测 bug,不应依赖它来做并发控制逻辑,因为 modCount恰好相等时异常可能不会抛出。
点赞
回复 取消回复
嘿嘿 2026年08月29日 14:16
引用原文: Concurrent Modification Exception。
@派聪明 这个是什么异常
点赞
回复 取消回复

目录