先由一道题引发思考:

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

ArraryList源码解读的更多相关文章

  1. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  2. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  3. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  4. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  5. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  6. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

  7. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

  8. AFNetworking 3.0 源码解读 总结(干货)(下)

    承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...

  9. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

随机推荐

  1. ubuntu httpie使用方法

    HTTPie 是用 Python 写的,所以你可以在几乎所有地方(Linux,MacOSX,Windows)安装它.而且,在大多数的 Linux 发行版中都有编译好的安装包. Debian,Ubunt ...

  2. python语言程序设计部分习题

    第二章 python程序实例解析 程序练习题 2.1   实例1的修改,采用eval(input(<提示内容>))替换现有输入部分,并使输出的温度值为整数. vv 2.2 汇率兑换程序.按 ...

  3. 链表实现比较高效的删除倒数第k项

    最近写链表不太顺,无限的段错误.今天中午写的链表删除倒数第k项,用的带尾节点的双向链表,感觉已经把效率提到最高了,还是超时,改了很多方法都不行,最 终决定看博客,发现原来是审题错了,阳历给的是以-1结 ...

  4. Win10家庭版安装Docker

    1.下载Docker Toolbox 下载地址:http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/ 2.安装Docker ...

  5. Spring IOC MVC DI简单实现

    目录的大致情况:所有的类都会加进来. 1.首先先写基本的Controller Service ServiceImpl Controller Service ServiceImpl是用来验证下面写的框架 ...

  6. hadoop之hdfs命令详解

    本篇主要对hadoop命令和hdfs命令进行阐述,yarn命令会在之后的文章中体现 hadoop fs命令可以用于其他文件系统,不止是hdfs文件系统内,也就是说该命令的使用范围更广可以用于HDFS. ...

  7. Spring Boot (四): Druid 连接池密码加密与监控

    在上一篇文章<Spring Boot (三): ORM 框架 JPA 与连接池 Hikari> 我们介绍了 JPA 与连接池 Hikari 的整合使用,在国内使用比较多的连接池还有一个是阿 ...

  8. fslove - Matlab求解多元多次方程组

    fslove - Matlab求解多元多次方程组 简介: 之前看到网上的一些资料良莠不齐,各种转载之类的,根本无法解决实际问题,所以我打算把自己的学到的总结一下,以实例出发讲解fsolve. 示例如下 ...

  9. 暑期——第九周总结(1,林子雨老师关于hdfs eclipse案例报错问题【已解决】)

    所花时间:7天 代码行:1000(Java)+500(Python)+300(C++) 博客量:1篇 了解到知识点 : 一: 解决"Class org.apache.hadoop.hdfs. ...

  10. 用Python帮你实现IP子网计算

    目录 0. 前言 1. ipaddress模块介绍 1.1 IP主机地址 1.2 定义网络 1.3 主机接口 1.4 检查address/network/interface对象 1.4.1 检查IP版 ...