在明确的场景下,为集合指定初始容量

简介:

我们经常使用ArrayList,Vector,Hashmap等集合,一般都是直接用new跟上类名声明出一个集合来,然后使用add,remove,等方法进行操作,而且因为它们是自动管理长度的,所以不用我们特别费心超长问题,这确实是一个非常好的优点,但也有我们需要注意的事项.

下面以ArrayList为例深入了解一下Java是如何实现长度的动态管理的,先从add方法的阅读开始.

复制代码
1 public boolean add(E e) {    
2         ensureCapacity(size + 1);     
3         elementData[size++] = e;    
4         return true;    
5     }    
复制代码

我们知道ArrayList是一个大小可变的数组,但它在底层使用的是数组存储(也就是elementData变量),而且数组是定长的,要实现动态长度必然要进行长度的扩展,ensureCapacity方法提供了此功能,代码如下:

复制代码
 1     public void ensureCapacity(int minCapacity) {    
 2         modCount++;         //修改计数器  
 3         int oldCapacity = elementData.length;      
 4         //当前需要的长度超过了数组长度,进行扩容处理  
 5         if (minCapacity > oldCapacity) {    
 6             Object oldData[] = elementData;    
 7             //新的容量 = 旧容量 * 1.5 + 1  
 8             int newCapacity = (oldCapacity * 3)/2 + 1;    
 9                 if (newCapacity < minCapacity)    
10                     newCapacity = minCapacity;    
11           //数组拷贝,生成新的数组   
12           elementData = Arrays.copyOf(elementData, newCapacity);    
13         }    
14     }  
复制代码

注意看新数组的长度计算方法,并不是增加一个元素,elementData的长度就加1,而是在达到了elementData长度的临界点时,才将elementData扩容1.5把倍,这样实现有什么好处呢?好处就是避免了多次调用copyOf()方法的性能开销,否则每增加一个元素都要扩容一次,那性能岂不是非常的糟糕.

为什么是1.5倍呢,因为一次扩容太大,占用的内存也就越大,浪费的内存也就越多(1.5倍扩容,最多浪费33%的数组空间,而2.5倍扩容则最多浪费60%的内存),而扩容太小(比如每次扩容1.1倍),则需要多次对数组重新分配内存,性能消耗严重,经过测试验证,扩容1.5倍即满足了性能要求,也减少了内存消耗.

elementData的默认长度是10,如果我们使用默认的方式生命ArrayList,如new ArrayList(),则elementData的初始长度就是10.我们来看ArrayList的无参构造:

复制代码
 1     // ArrayList无参构造函数。默认容量是10。    
 2     public ArrayList() {    
 3         this(10);    
 4     }    
 5     // ArrayList带容量大小的构造函数。    
 6     public ArrayList(int initialCapacity) {    
 7         super();    
 8         if (initialCapacity < 0)    
 9             throw new IllegalArgumentException("Illegal Capacity: "+    
10                                                initialCapacity);    
11         // 新建一个数组    
12         this.elementData = new Object[initialCapacity];    
13     }  
复制代码

默认初始化时声明了一个长度为10的数组 在通过add方法增加第11个元素时,ArrayList类就自动扩展了,新的elementData数组长度就是(10*3)/2 +1 也就是16,当增加到第17个元素时再次扩容为(16*3)/2+1 也就是25,以此类推,实现了ArrayList的动态数组管理.

 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5422175.html,如需转载请自行联系原作者

相关文章
|
7月前
|
算法
HashMap的默认初始长度是多少?为什么?
HashMap的默认初始长度是多少?为什么?
115 0
|
存储 容器
List,linkeedlist集合介绍,特点,二者区别,增长因子,去重复
List,linkeedlist集合介绍,特点,二者区别,增长因子,去重复
|
4月前
|
编译器 数据库 vr&ar
|
6月前
|
算法 C++ 容器
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
288 0
|
7月前
|
人工智能 分布式计算 Java
【c++】初始c++
【c++】初始c++
【c++】初始c++
|
JavaScript Python
从列表中或数组中随机抽取固定数量的元素组成新的数组或列表
从列表中或数组中随机抽取固定数量的元素组成新的数组或列表
74 0
|
存储 Java
HasMap初始容量设置
HasMap初始容量设置
105 0
|
机器学习/深度学习 人工智能 算法
【算法 | 实验8】分配最小页数(数组划分和最大值最小化问题)
【算法 | 实验8】分配最小页数(数组划分和最大值最小化问题)
289 0
【算法 | 实验8】分配最小页数(数组划分和最大值最小化问题)