ArrayList源码解析

在面试的时候都会问集合ArrayList和linkList,然后你说ArrayList查询快,增删慢,然后面试官问为什么?
。。。。。。

你可以回答:

ArrayList是基于数组的,是有下标的,查询的时候指定下标,一下就查到了。

而增删慢的原因是因为增加和删除的时候它要创建一个新的数组并且扩容或者删除前移,然后复制过去,每次扩容是原来的1.5倍。

jdk1.7初始化数组10个,1.8初始化0,懒汉式

ArrayList还实现了自己的序列化,比如数组长度是10,里面可能只有一个元素,其他都是null,这时候使用默认的序列化就打印出9个null,所以ArrayList的数组加上transient关键字表示不用默认的序列化,重写writeObject和readObject方法,根据size序列化

最重要的是ArrayList是线程不安全的,可以用vector,vector的方法都进行了synchronized加锁,所以是线程安全的,但是效率比较低,所以可以用CopyOnWriteArrayList来实现线程安全,他的查询代码是不加锁的,并且在新增和删除的时候会复制出一份来修改,这时候如果同时有线程进行查询就会查询到老的,不影响

线程不安全的场景比如

 一个if判断有这个元素就取出,结果线程A进了这个判断,线程B正好删了,就会有问题,所以CopyOnWriteArrayList在写的时候选择再复制一份出来,线程B改的是新的,线程A还是读取旧的,不会有问题。但缺点是总是复制写的性能,以及只能保证最终一致,因为在写的时候,读的是旧的。

 

下面开始瞅瞅源码

ArrayList源码解析

elementData是存储数据的对象,size是集合的大小,与数组的length不同,代表实际存储的数量

ArrayList源码解析

构造方法有3个:

空构造方法:初始化数组为空数组

传入大小构造:创建一个指定大小的数组

传入集合构造:数组对象=elementData.toArray(),然后改变大小size,如果传入的是null,这里会空指针

ArrayList源码解析

get方法很简单,判断传入的下标有没有越界,如果有就抛异常,没有就直接返回值,强转成泛型

ArrayList源码解析

set方法也是检查数组下标越界之后,获取原先的老值,然后赋值新值,把老值返回。

ArrayList源码解析

重点的add方法,调用ensureCapacityInternal方法判断是否需要扩容,扩容方法下面会讲。

然后size++,对应下一个下标进行赋值。

ArrayList源码解析

remove方法

 

扩展知识:

LIst去重,转成Set再转回来就可以了,如果是对象,记得重写equals

new ArrarList(new HashMap(list));

 

List和数组的互转

list转数组:list.toArray()

数组转list:Arrays.asList(list)