先由一道题引发思考:

ArrayList list = new ArrayList(20);中的list扩充几次()

A 0     B 1     C 2      D 3

答案:A

直接翻看 jdk1.8 源码ArrayList,初始化共有三种方式;

 /**
* 默认初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 共享空数组实例,用于空实例。调用构造函数容量为0时,会赋予数据的数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 共享空数组实例用于默认大小的空实例。使用默认构造函数时,会赋予数据的数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储ArrayList元素的数组缓冲区。 ArrayList的容量是此数组缓冲区的长度。在第一次
* 加入元素时,任何空实例(elementData ==
* DEFAULTCAPACITY_EMPTY_ELEMENTDATA)会扩充成默认大小
*/
transient Object[] elementData;
/**
* ArrayList的大小
*/
private int size;

第一种:有参构造方法,通过指定大小来初始化内部的数组,无需动态扩容。因此前面问题答案是不需要扩容。

    public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
 第二种:无参的构造方法,以默认的大小来初始化内部的数组,需动态扩容。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

第三种:Collection对象来构造,并将该集合的元素添加到ArrayList。

    public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

无参构造方法的实现:

ArraryList使用 add() 添加元素的过程,调用链 add()->ensureCapacityInternal()->ensureExplicitCapacity()->grow()

    public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
    private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
    private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

当第一次添加元素,空实例会被赋予默认容量10,此时并未扩容,直到添加第11个元素,进入grow()方法扩容,新的容量= 旧容量 + 旧容量/2 ,第一次扩容后容量为15,以此类推第二次扩容后容量

为15+15/2 = 22

      

当使用的是addAll()添加集合时,

    public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}

当list 使用addAll() 添加集合时,第一次扩容后容量为15,但是还是小于需要最小容量20,因此将需要的最小容量赋值给新容量,扩容后新容量为20;参考源码,grow() 方法中 if (newCapacity - minCapacity < 0)   newCapacity = minCapacity; 有趣的是 modCount 为 6 ,因为此时的list只做了6次操作。

Collection对象来构造的实现:

使用集合来创建ArraryList对象,elementData的容量即为集合的大小。此时的modCount 为0;参照源码集合对象构造方法实现,即可明白。

 

总结:

有参构造方法,通过指定大小来初始化内部的数组,无需扩容,容量即为指定大小;

集合对象的构造方法,容量即为集合大小;

无参的构造方法,扩容后的新容量为旧容量的1.5倍,如果所需最小容量仍大于新容量,则将所需的最小容量赋值给新容量。如果扩容后的新容量超过限制的容量,则用所需的最小容量与限制的容量进行判断,所需的最小容量大于限制的容量则指定为Integer的最大值2^31-1,否则指定为限制容量大小(2^31-1)-8。然后通过数组的复制将原数据复制到一个更大(新的容量大小)的数组。

本文参考文章:http://www.cnblogs.com/ggmfengyangdi/p/5738491.html

关于ArraryList 面试参考文章:

http://www.importnew.com/9928.html  

https://blog.csdn.net/qq_38859786/article/details/80265851

最新文章

  1. 【转】WPF DataGrid 获取选中的当前行某列值
  2. 2016 年 50 个最佳的轻量级 JavaScript 框架和库
  3. IOS 本地推送 IOS10.0以上 static的作用 const的作用
  4. mac上开启ftp
  5. linux命令:mkdir命令
  6. Ecshop文章列表页显示内容摘要
  7. dede数据库类使用方法$dsql【转】
  8. setAnimationTransition:forView:cache: 运行动画时背景色问题
  9. Activity大致会经过如下四个状态
  10. 【LeetCode练习题】Next Permutation
  11. 【C++探索之旅】第一部分第二课:C++编程的必要软件
  12. vultr vps发布多用户管理功能
  13. AVFoundation自定义拍照
  14. Laravel 验证中文本地化
  15. JDK及JRE目录结构
  16. Java SPI机制用法demo
  17. idea 排除编译 参考
  18. python 模型 ORM简介
  19. [Swift实际操作]八、实用进阶-(1)Swift语言中的两种单例模式实际操作
  20. CentOS release 6.5 yum安装报错

热门文章

  1. 论文阅读 | DeepDrawing: A Deep Learning Approach to Graph Drawing
  2. SpringBoot 2.0 + InfluxDB+ Sentinel 实时监控数据存储
  3. [LeetCode] 由 “打印机任务队列&quot; 所想
  4. C++基础之迭代器
  5. Spring入门(十四):Spring MVC控制器的2种测试方法
  6. linux双网卡绑定为逻辑网卡
  7. Scala Data Structure
  8. 如何把安全证书导入到java中的cacerts证书库
  9. 微信小程序项目-你是什么垃圾?
  10. 『TensorFlow2.0正式版』TF2.0+Keras速成教程&#183;零:开篇简介与环境准备