Fork me on Gitee

Java集合类-ArrayList源码解析

看JDK源码,个人感觉可以从属性、构造方法、常用方法着手,再通篇学习源码。
JDK:1.8.0_121
Idea:2018.3.4

简介

ArrayList是一个容量动态扩张的集合,实现了RandomAccess接口,支持随机访问,初始容量10,最大容量Integer.MAX_VALUE - 8(2147483640),每次调用ArrayList的新增或者删除等修改方法,继承自AbstactList抽象类的属性modCount都会自增,当通过Interactor遍历集合时,只要modCount被其他线程修改,就会抛出ConcurrentModificationException。ArrayList是线程不安全的类,因为它的操作自身集合属性的方法没有进行同步也不是原子性操作,所以会出现不一致现象,可以通过List list = Collections.synchronizedList(new ArrayList(…))把它转成线程安全的集合,当然只是封装了对ArrayList的操作,保存同步而已,性能不是很高,所有的修改操作都要一个个同步。

概览

类图

类图

类型定义
1
2
3
4
5
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{

}

属性

来自自身的成员变量:

1
2
3
4
5
6
7
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10
private static final Object[] EMPTY_ELEMENTDATA = {}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

来自父类和接口的成员变量:

1
protected transient int modCount = 0;

刚开始学Java的时候,我们掌握了一条定理:ArrayList是底层通过数组实现的。

  • elementData
    真正存放对象的数组
  • DEFAULT_CAPACITY
    默认初始化容量
  • serialVersionUID
    序列化ID,序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。
  • EMPTY_ELEMENTDATA
    使用部分构造方法创建对象时,给elementData赋值的空数组
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    使用默认构造方法创建对象时,给elementData赋值的默认空数组
  • modCount
    操作技术,对elementData操作时会调整modCount
  • MAX_ARRAY_SIZE
    数组的最大长度,当超过此值会,数组允许扩容到Integer.MAX_VALUE

问题1:elementData前添加了transient,我们知道transient的作用是让某些被修饰的成员属性变量不被序列化,那么在执行时序列化时,为何输出了elementData中的对象?

构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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;
}

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;
}
}
感谢您发财的小手,我们一起进步
TEC-CHEN 微信支付

微信支付

TEC-CHEN 支付宝

支付宝

TEC-CHEN 微信-赞赏码

微信-赞赏码


-------------本文结束感谢您的阅读-------------
0%