前言

数组是我们最常用最简单的数据结构,Java里对数组做了一个简单的包装,就是ArrayList,提供自动扩容的功能。

最常用法

list在我们日常代码中最为常用的做法是创建一个list,放入数据,取出数据。如下:

@Test
public void testList(){
final List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("a"); final String one = list.get(0);
final int size = list.size(); Assert.assertEquals("a", one);
Assert.assertEquals(4, size);
}

下面,将从构造函数开始读取源码。

构造器

第一步,构造一个list对象


/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

注释写的很清楚,构造一个空list,初始化容量为10. 我们来看看这个初始值。

/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

默认大小的共享的空array实例。可以注意到这是一个static变量,也就是说所有的ArrayList对象共享这个变量。由此可以猜测,这是一个临时值。

然后看我们的数据存储对象elementData.

/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

ArrayList的容量(capacity)就是这个数组的长度。

另外,注意修饰关键字transient, 这个不常用,用来表示这个字段不可以被序列化。我们知道,ArrayList实现了Serializable接口,为什么不允许序列化data呢?具体原因参加 http://www.cnblogs.com/woshimrf/p/java-serialize.html

add

public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

先保证容量,然后插入数据,size数量+1.

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}

针对空list第一次add,判断elementData是不是默认的空对象,若是空对象,计算容量。容量的计算也很有意思。

private static final int DEFAULT_CAPACITY = 10;

第一次添加后容量就是10了,当超过10之后就肯定要扩容了。

private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

再一次看到modCount这个变量名,和HashMap一样,记载容量发生变化的次数。而扩容的阈值也相当简单,只要保证当前数量+1能够容纳就好。当数组长度不够的时候,扩容。


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);
}

扩容扩大为1.5倍。然后新建数组,长度为新的容量,复制旧数据。由于过程中没有加锁,ArrayList也不是线程安全的。

Get

public E get(int index) {
rangeCheck(index); return elementData(index);
}

实现相当简单,就是通过数组下标读取元素。但值得学习的是编程结构。比如,这个的范围检测,通过一个有意义的方法名封装了一段代码。清晰易懂。

private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

如何使用线程安全的List

自己对变化过程加锁,或者使用

List list = Collection.synchronizedList(new ArrayList());

CopyOnWriteArrayList是一个有趣的例子,它规避了只读操作(如get/contains)并发的瓶颈,但是它为了做到这点,在修改操作中做了很多工作和修改可见性规则。 此外,修改操作还会锁住整个List,因此这也是一个并发瓶颈。所以从理论上来说,CopyOnWriteArrayList并不算是一个通用的并发List。(并发编程网)

参考

ArrayList源码阅读的更多相关文章

  1. java8 ArrayList源码阅读

    转载自 java8 ArrayList源码阅读 本文基于jdk1.8 JavaCollection库中有三类:List,Queue,Set 其中List,有三个子实现类:ArrayList,Vecto ...

  2. ArrayList源码阅读笔记(1.8)

    目录 ArrayList类的注解阅读 ArrayList类的定义 属性的定义 ArrayList构造器 核心方法 普通方法 迭代器(iterator&ListIterator)实现 最后声明 ...

  3. ArrayList源码阅读(小白的java进阶)

    ArrayList(线程不安全) ArrayList是一个其容量能够动态增长的动态数组 继承关系 构造方法 是符合collection父接口的规范的 //传0则设置为默认容量 public Array ...

  4. ArrayList源码阅读笔记(基于JDk1.8)

    关键常量: private static final int DEFAULT_CAPACITY = 10; 当没有其他参数影响数组大小时的默认数组大小 private static final Obj ...

  5. ArrayList源码阅读----JDK1.8

    //定义一个默认的长度10 private static final int DEFAULT_CAPACITY = 10; //定义空的数组 private static final Object[] ...

  6. ArrayList源码阅读笔记

    ArrayList ArrayList继承自AbstractList抽象类,实现了RandomAccess, Cloneable, java.io.Serializable接口,其中RandomAcc ...

  7. Java核心复习 —— ArrayList源码阅读

    一.ArrayList 介绍 ArrayList是List接口可变数组的实现. 特点 非线程安全 查找和修改效率高 二.ArrayList 使用方法 remove元素 @Test public voi ...

  8. 【JDK1.8】JDK1.8集合源码阅读——ArrayList

    一.前言 在前面几篇,我们已经学习了常见了Map,下面开始阅读实现Collection接口的常见的实现类.在有了之前源码的铺垫之后,我们后面的阅读之路将会变得简单很多,因为很多Collection的结 ...

  9. JDK 1.8源码阅读 ArrayList

    一,前言 ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用. 二,ArrayList ...

随机推荐

  1. JAVA BASE64

    Base64编码说明:     Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式. 如果剩下的字符不足3个字节, ...

  2. mysql-冗余和重复索引

    mysql允许在相同列上创建多个索引,无论是有意还是无意,mysql需要单独维护重复的索引,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能. 重复索引是指的在相同的列上按照相同的顺序创建 ...

  3. linkin大话面向对象--构造器详解

       对象的产生格式:类名称  对象名 = new  类名称(); 因为有(),所以是方法,实际上它就是构造方法,并且是非私有的构造方法.如:CellPhone cp = new CellPhone( ...

  4. c#后台调用API

    前两周赶上项目第一个版本上线,着实忙了一把,毕竟只有两个人负责.如今已完结,总算喘了一口气,现在任务就是写API.测API,许久之前写过JS前台调用 项目API,也写过后台调用开放的手机号归属地查询, ...

  5. 面试中的TCP协议

    TCP的三次握手和四次挥手 三次握手 TCP连接是通过三次握手来连接的. 第一次握手 当客户端向服务器发起连接请求时,客户端会发送同步序列标号SYN到服务器,在这里我们设SYN为x,等待服务器确认,这 ...

  6. Django----模板层

    一.模板层:           python的模板:HTML代码+模板语法      模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签. import datetime t=dateti ...

  7. 基于tomcat+springMVC搭建基本的前后台交互系统

    一.摘要 1.所需软件列表: 1) tomcat :  apache-tomcat-7.0.54  服务端容器 2) Intellij: Intellij IDEA 14.0.3         开发 ...

  8. Python学习笔记(三): 收集参数

    如下代码: >>>def print_params(title,*params) print title print params >>>print_params( ...

  9. Asp.net mvc 下载文件

    前言 最近有需求需要下载文件,可能是image的图片,也可能是pdf报告,也可能是微软的word或者excel文件. 这里就整理了asp.net mvc 和asp.net webapi 下载的方法 A ...

  10. radare2逆向笔记

    最近刚开始学习逆向(Reverse Engineering), 发现其学习曲线也是挺陡峭的, 而网上的 许多writeup文章主旨总结就六个字:"你们看我屌吗?" ...几近炫技而 ...