HashMap和ConcurrentHash进行初始化时inittialCapacity的区别

探讨HashMap与ConcurrentHashMap中initialCapacity参数的区别。HashMap中该参数直接决定数组大小,而ConcurrentHashMap中则根据该参数及负载因子计算出数组大小。

问题描述:我们在new HashMap(16)和new ConcurrentHashMap(16)时,这两个16有什么区别呢?

结论:

HashMap中initialCapacity指数组大小,比如指定inittialCapacity为16,那么初始化创建的数组大小就是16;

ConcurrentHashMap中inittialCapacity指ConcurrentHashMap的容量,而不是数组大小。比如,如果指定inittialCapacity为16,负载因子为0.75,那么初始化创建的数组大小为32(inittialCapacity/0.75+1,在通过tableSizeFor()取不小于这个数的2次方)。

所以感觉ConcurrentHashMap的inittialCapacity更符合我们平时所说的初始容量的语义。

代码分析:

HashMap:

可以看到,HashMap经过一系列的边界检查后,通过tabeSizeFor(initialCapacity)这个方法进行赋值给this.threshold。

先说tabeSezeFor(inittialCapacity)方法,这个方法主要是返回一个不小于输入值的最小2次方整数。有点拗口,简单说就是如果输入15,则不小于15的最小2次方整数就是16,如果输入16,则返回16。

再说this.threshold,这个字段其实是用于扩容判断,比如每次添加元素要判断HashMap中元素是否超过threshold,如果超过,则要进行扩容。而HashMap中没有专门的字段保存初始容量,所以将通过tabeSizeFor(inittialCapacity)计算的初始容量保存在了this.threshold。

HashMap的初始化是采取懒初始化的方式,就是说我们执行new HashTable(16),实际上这个时候没有进行内部数组的初始化,而是在我们插入元素的时候才new数组。

所以说当我们往HashTalbe中插入元素时,HashTable会将this.threshold的值取出,初始化数组。因此,HashTable中的initialCapacity其实是指HashTable中数组的大小。

ConcurrentHashMap:

ConcurrentHashMap进行了边界检查后,将通过tableSizeFor(inittialCapacity)取不小于inittialCapacity/loadFactor+1的最小2次方整数。比如inittialCapacity为16,loadFactor为0.75,最后通过tableSizeFor()运算得32。最后将这个数存入this.sizeCtl。ConcurrentHashMap也是在插入的时候才取出这个数进行数组初始化。

所以,ConcurrentHashMap中的inittialCapacity是指HashMap的容量,不是指的数组大小,实际初始化的数组要比inittialCapacity大。

<think> 我们正在讨论Java中的HashMapArrayList的初始化容量扩容因子。 首先,我们来分别讨论这两个类。 1. ArrayList: - 默认初始化容量:在Java中,ArrayList的默认初始容量是10。 - 扩容因子:当ArrayList需要扩容,它会增加当前容量的50%。也就是说,新容量 = 当前容量 + 当前容量 / 2(即1.5倍)。 - 扩容机:当添加元素,如果当前元素个数已经等于容量(即数组已满),就会触发扩容。 2. HashMap: - 默认初始化容量:在Java 8中,HashMap的默认初始容量是16。 - 扩容因子(加载因子):默认是0.75。这个加载因子是用于决定何进行扩容的阈值。 - 扩容机制:当HashMap中的元素数量(即键值对数量)超过当前容量乘以加载因子(capacity * load factor),就会触发扩容。扩容后的容量是原来的2倍(即新容量 = 旧容量 * 2)。 下面我们分别给出示例代码来展示ArrayListHashMap初始化,并演示扩容行为(但请注意,我们不能直接获取内部容量,因此只能通过观察大小变化来推断)。 但是注意:我们通常不会直接访问内部容量,但我们可以通过反射来查看(这里不推荐在生产环境中使用反射)。下面我们通过添加元素直到触发扩容来观察。 不过,这里我们主要关注的是默认值,所以给出初始化代码默认值。 ArrayList示例代码: </think> ### HashMap初始化容量扩容因子 在 Java 中,`HashMap` 的默认初始化容量是 **16**(即数组的初始大小),默认加载因子(扩容因子)是 **0.75**。当元素数量超过 `容量 × 加载因子` ,触发扩容,新容量为旧容量的 **2 倍**。 ```java import java.util.HashMap; public class HashMapExample { public static void main(String[] args) { // 默认初始化容量=16, 加载因子=0.75 HashMap<String, Integer> map = new HashMap<>(); // 添加12个元素(16*0.75=12)不会扩容 for (int i = 0; i < 12; i++) { map.put("key" + i, i); } System.out.println("Size before resize: " + map.size()); // 输出12 // 添加第13个元素触发扩容(容量从16→32) map.put("key12", 12); System.out.println("Size after resize: " + map.size()); // 输出13 } } ``` #### 关键点解释: 1. **初始化容量**:未指定默认为 `16`(可通过构造函数自定义)。 2. **加载因子 `0.75`**:平衡间与空间开销的经验值。过高导致哈希冲突增加,过低导致频繁扩容。 3. **扩容规则**:新容量 = 旧容量 × 2,需重新计算所有元素的哈希位置(耗操作)。 --- ### ArrayList 的初始化容量扩容因子 在 Java 中,`ArrayList` 的默认初始化容量是 **10**。当元素数量超过当前容量,触发扩容,新容量为旧容量的 **1.5 倍**(即 `旧容量 + 旧容量 >> 1`)。 ```java import java.util.ArrayList; public class ArrayListExample { public static void main(String[] args) { // 默认初始化容量=10 ArrayList<Integer> list = new ArrayList<>(); // 添加10个元素(容量=10)不会扩容 for (int i = 0; i < 10; i++) { list.add(i); } System.out.println("Size before resize: " + list.size()); // 输出10 // 添加第11个元素触发扩容(容量从10→15) list.add(11); System.out.println("Size after resize: " + list.size()); // 输出11 } } ``` #### 关键点解释: 1. **初始化容量**:未指定默认为 `10`(可通过构造函数自定义)。 2. **扩容规则**:新容量 = 旧容量 × 1.5(实际计算:`int newCapacity = oldCapacity + (oldCapacity >> 1)`)。 3. **扩容开销**:需复制整个数组到新内存空间,间复杂度 O(n)。 --- ### 总结对比 | **集合类型** | 默认初始化容量 | 扩容因子 | 扩容倍数 | |--------------|----------------|----------|----------| | `HashMap` | 16 | 0.75 | ×2 | | `ArrayList` | 10 | 动态触发 | ×1.5 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值