ArrayList源码
Posted 秋天de枫叶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList源码相关的知识,希望对你有一定的参考价值。
ArrayList在编程中是比较常用的一个集合,ArrayList类是一个特殊的数组,通过添加和删除元素,就可以动态改变数组的长度。
public class ArrayList<E>extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
ArrayList继承了AbstractList类,实现了List。即:具有了添加,删除,修改,遍历等功能。
ArrayList实现了RandomAccess接口,即:能通过元素的序号快速访问对象。
ArrayList实现了Cloneable接口,即:能被克隆。
ArrayList实现了Serializable接口,即:支持序列化,能通过序列化传输。
// ArrayList带容量大小的构造函数。
public ArrayList(int initialCapacity)
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 新建一个数组
this.elementData = new Object[initialCapacity];
// ArrayList构造函数。默认容量是10。
public ArrayList()
this(10);
// 创建一个包含collection的ArrayList
public ArrayList(Collection<? extends E> c)
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
// 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2+1”
public void ensureCapacity(int minCapacity)
// 将“修改统计数”+1
modCount++;
int oldCapacity = elementData.length;
// 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
if (minCapacity > oldCapacity)
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
通过构造函数可以看出,在使用ArrayList时,如果不设定初始容量的,ArrayList默认容量为10,因为ArrayList是动态数组,所以当容量不够时,ArryList会自动扩容的。自动扩容分两种情况,假设原来数组容量为10,并且已经有5个容量应经占用了,现在有要想数组中添加20 个元素。这时就需要考虑了,ArrayList扩容一次的容量为10x3/2+1=16, 16<20。说明扩容后的容量还是小于当前要添加的元素的个数,所以,ArrayList 直接将元素的个数当成现在要扩容的容量。也就是说,现在ArrayList的容量为30。
所以ArrayList 扩容分两种情况:
第一种:当要添加的元素个数,小于ArrayList扩容后容量时,Arraylist容量="(原始容量x3)/2+1"。
第二种:当添加的元素个数,大于ArrayList扩容后的容量时,ArrayList容量=当前容量+元素的个数。
ArrayList线程不安全,为什么说ArrayList线程不安全呢?
假设:
在 Items[Size]的位置存放此元素;
增大 Size 的值。
在单线程运行的情况下,如果 Size= 0,添加一个元素后,此元素在位置 0,而且 Size=1;
如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList添加元素,因为此时 Size 仍然等于 0(注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size的值。
public static void main(String[] args) throws InterruptedException
ThreadGroup group = new ThreadGroup("testgroup");
ArrayListInThread t = new ArrayListInThread();
for (int i = 0; i < 10000; i++)
Thread th = new Thread(group, t, String.valueOf(i));
th.start();
while (group.activeCount() > 0)
Thread.sleep(10);
System.out.println();
// it should be 10000 if thread safe collection is used.
System.out.println(t.list1.size());
public class ArrayListInThread implements Runnable
List<String> list1 = new ArrayList<String>(1);// not thread safe
// List<String> list1 = Collections.synchronizedList(new
// ArrayList<String>());// thread safe
public void run()
try
Thread.sleep((int) (Math.random() * 2));
catch (InterruptedException e)
e.printStackTrace();
list1.add(Thread.currentThread().getName());
总结
1.ArrayList是一个线程不安全的集合
2.ArrayList因为是一个有序的集合,通过元素序号可以快速访问。但是在增删时比较慢。因为需要移动元素位置。
3.ArrayList是一个动态的数组,她的扩容方式分两种情况。
第一种:当要添加的元素个数,小于ArrayList扩容后容量时,Arraylist容量="(原始容量x3)/2+1"。
第二种:当添加的元素个数,大于ArrayList扩容后的容量时,ArrayList容量=当前容量+元素的个数。
以上是关于ArrayList源码的主要内容,如果未能解决你的问题,请参考以下文章