Java集合 ArrayList 源代码
- ArrayList简介
- Arraylist的必备知识点总结
- (一) jdk1.8和jdk1.7的扩容区别
- (二)ArrayList与LinkedList的区别有哪些?
- 对于 ArrayList 来说:
- 1)get(int index)
- 2)add(E e)
- 3)add(int index, E element)
- 4)remove(int index)
- 对于对于 LinkedList 来说:
- 1)get(int index)
- 2)add(E e)
- 3)add(int index, E element)
- 4)remove(int index)
- (三)ArrayList与Vector的区别?
- (1)同步性:
- (2)数据增长:
- (四)ArrayList的底层是数组,数组的名称是什么?类型是什么?
- (五)LinkedList的底层是什么?
- (六)ArrayList里面可以存null吗?
- (七)ArrayList的底层是数组,它和数组有什么区别吗?
- (八)当向ArrayList集合中添加元素时需要调用add()方法,add()方法的执行流程是怎样的?
- (九)在调用ArrayList的remove(int index)方法时,执行流程是怎样的?
- (十) 在ArrayList的增、删、改、查中,什么地方会修改modCount?
- (十一) ArrayList的时间复杂度是多少?
- (十二)为什么ArrayList在增、删的时候效率低?
- 方法详解
- 1、add(Object element): 向列表的尾部添加指定的元素。
- 2、size(): 返回列表中的元素个数。
- 3、get(int index): 返回列表中指定位置的元素,index从0开始。
- 4、add(int index, Object element): 在列表的指定位置插入指定元素。
- 5、set(int i, Object element): 将索引i位置元素替换为元素element并返回被替换的元素。
- 6、clear(): 从列表中移除所有元素。
- 7、isEmpty(): 判断列表是否包含元素,不包含元素则返回 true,否则返回false。
- 8、contains(Object o): 如果列表包含指定的元素,则返回 true。
- 9、remove(int index): 移除列表中指定位置的元素,并返回被删元素。
- 10、remove(Object o): 移除集合中第一次出现的指定元素,移除成功返回true,否则返回false。
- 11、iterator(): 返回按适当顺序在列表的元素上进行迭代的迭代器。
- 源码
Java集合工具包位于Java.util包下,包含了很多常用的数据结构,如数组、链表、栈、队列、集合、哈希表等。学习Java集合框架下大致可以分为如下五个部分:List列表、Set集合、Map映射、迭代器(Iterator、Enumeration)、工具类(Arrays、Collections)。
Java集合框架图:
从上图中可以看出,集合类主要分为两大类:Collection和Map。
Collection是List、Set等集合高度抽象出来的接口,它包含了这些集合的基本操作,它主要又分为两大部分:List和Set。
今天我们说的Java集合类之 ArrayList
ArrayList简介
ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List
l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。
Arraylist的必备知识点总结
(一) jdk1.8和jdk1.7的扩容区别
ArrayList在JDK1.8与JDK1.7底层区别
JDK1.7:ArrayList像 饿汉式 ,直接创建一个初始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍
JDK1.8:ArrayList像 懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍
准确的来说,不是在无参方法构造赋的值为10,一开始new ArrayList();的时候是0,第一次调用add()方法的时候才赋值10的
(二)ArrayList与LinkedList的区别有哪些?
家人们 来自阿里面试官的问题:好好听,虽然我讲得不好
ArrayList 内部使用的动态数组来存储元素,LinkedList 内部使用的双向链表来存储元素,这也是 ArrayList 和 LinkedList 最本质的区别。
对于 ArrayList 来说:
1)get(int index)
get(int index) 方法的时间复杂度为 O ( 1 ) ,因为是直接从底层数组根据下标获取的,和数组长度无关。这也是 ArrayList 的最大优点。
// 获取index位置的元素值
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
2)add(E e)
add(E e) 方法会默认将元素添加到数组末尾,但需要考虑到数组扩容的情况,如果不需要扩容,时间复杂度为 O ( 1 )。
// 将e 添加到ArrayList中
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// 将e添加到ArrayList的指定位置
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
但是 这个的话 需要考虑 是否超出容器的大小 看是否需要扩容 如果需要扩容的话,并且不是第一次(oldCapacity > 0)扩容的时候,内部执行的 Arrays.copyOf() 方法是耗时的关键,需要把原有数组中的元素复制到扩容后的新数组当中。
*这个点 我不太明白 因为我没看到我的源码,不过看一个大佬写的是如下源代码 *
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);
}
3)add(int index, E element)
add(int index, E element) 方法将新的元素插入到指定的位置,需要先通过遍历查找这个元素,然后再进行插入,所以时间复杂度为 O ( n )。
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
4)remove(int index)
remove(int index) 方法将指定位置上的元素删除,考虑到需要复制底层数组,所以时间复杂度为 O ( n )
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
对于对于 LinkedList 来说:
1)get(int index)
get(int index) 方法的时间复杂度为 O ( n ) ,因为需要循环遍历整个链表。
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
LinkedList.Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
LinkedList.Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
LinkedList.Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
下标小于链表长度的一半时,从前往后遍历;否则从后往前遍历,这样从理论上说,就节省了一半的时间。
如果下标为 0 或者 list.size() - 1 的话,时间复杂度为 O ( 1 ) O(1)O(1)。这种情况下,可以使用 getFirst() 和 getLast() 方法。
public E getFirst() {
final LinkedList.Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
public E getLast() {
final LinkedList.Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
first 和 last 在链表中是直接存储的,所以时间复杂度为 O ( 1 ) 。
2)add(E e)
add(E e) 方法默认将元素添加到链表末尾,所以时间复杂度为 O ( 1 ) O(1)O(1)。
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final LinkedList.Node<E> l = last;
final LinkedList.Node<E> newNode = new LinkedList.Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
3)add(int index, E element)
add(int index, E element) 方法将新的元素插入到指定的位置,需要先通过遍历查找这个元素,然后再进行插入,所以时间复杂度为 O ( n )
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
如果下标为 0 或者 list.size() - 1 的话,时间复杂度为 O ( 1 ) 。这种情况下,可以使用 addFirst() 和 addLast() 方法。
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final LinkedList.Node<E> f = first;
final LinkedList.Node<E> newNode = new LinkedList.Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
linkFirst() 只需要对 first 进行更新即可。
public void addLast(E e) {
linkLast(e);
}
void linkLast(E e) {
final LinkedList.Node<E> l = last;
final LinkedList.Node<E> newNode = new LinkedList.Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
linkLast() 只需要对 last 进行更新即可。
需要注意的是,有些文章里面说,LinkedList 插入元素的时间复杂度近似 O ( 1 ),其实是有问题的,因为 add(int index, E element) 方法在插入元素的时候会调用 node(index) 查找元素,该方法之前我们之间已经确认过了,时间复杂度为 O ( n ),即便随后调用 linkBefore() 方法进行插入的时间复杂度为 O ( 1 ),总体上的时间复杂度仍然为 O ( n )才对。
void linkBefore(E e, LinkedList.Node<E> succ) {
// assert succ != null;
final LinkedList.Node<E> pred = succ.prev;
final LinkedList.Node<E> newNode = new LinkedList.Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
4)remove(int index)
remove(int index) 方法将指定位置上的元素删除,考虑到需要调用 node(index) 方法查找元素,所以时间复杂度为 O ( n )。
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
E unlink(LinkedList.Node<E> x) {
// assert x != null;
final E element = x.item;
final LinkedList.Node<E> next = x.next;
final LinkedList.Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
需要注意
如果列表很大很大,ArrayList 和 LinkedList 在内存的使用上也有所不同。LinkedList的每个元素都有更多开销,因为要存储上一个和下一个元素的地址。ArrayList 没有这样的开销。
但是,ArrayList 占用的内存在声明的时候就已经确定了(默认大小为 10),不管实际上是否添加了元素,因为复杂对象的数组会通过null 来填充。LinkedList 在声明的时候不需要指定大小,元素增加或者删除时大小随之改变。另外,ArrayList 只能用作列表;LinkedList 可以用作列表或者队列,因为它还实现了 Deque 接口。
(三)ArrayList与Vector的区别?
(1)同步性:
Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编
写线程安全的代码。
(2)数据增长:
ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需
要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认增长为原来两倍,而ArrayList的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。 ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提 供设置增长空间的方法。
总结:即Vector增长原来的一倍,ArrayList增加原来的0.5倍。
(四)ArrayList的底层是数组,数组的名称是什么?类型是什么?
名称是elementData,类型是Object[],所以ArrayList里面可以存放任意类型的元素。
(五)LinkedList的底层是什么?
双向链表
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
/**
* Links e as last element.
*/
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
(六)ArrayList里面可以存null吗?
可以,ArrayList存储的类型是object,null属于object类型。
private void printList() {
List<Integer> dataList = new ArrayList<>();
dataList.add(1);
dataList.add(null);
dataList.add(null);
for (Integer d : dataList) {
System.out.println(d);
}
System.out.println("------------------------");
for (Integer d : dataList) {
if (d != null) { // 需要这个判断吗?
System.out.println(d);
}
}
}
1
null
null
------------------------
1
(七)ArrayList的底层是数组,它和数组有什么区别吗?
Array 可以包含基本类型和对象类型,ArrayList 只能包含对象类型。
Array 大小是固定的,ArrayList 的大小是动态变化的。
ArrayList 提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
(八)当向ArrayList集合中添加元素时需要调用add()方法,add()方法的执行流程是怎样的?
调用add()方法时,add()方法首先调用ensureCapacityInternal()来判断elementData数组容量是否足够,ensureCapacityInternal()之所以能够判断,是因为它内部调用了ensureExplicitCapacity()方法,这个方法才是真正判断elementData数组容量是否够用的关键方法。如果容量足够,则直接将元素添加到ArrayList中;如果容量不够,则ensureExplicityCapacity()方法内部会调用grow()方法来对数组进行扩容。扩容成功之后,再将元素添加到ArrayList扩容之后的新数组中。
注意:如何扩容呢?会先创建一个原来数组1.5倍大小的新数组,然后将数据拷贝到新数组中。
(九)在调用ArrayList的remove(int index)方法时,执行流程是怎样的?
首先判断index是否合理,如果合理的话,会调用System.arraycopy()方法把指定下标到数组末尾的元素向前移动一个单位,并且会把数组最后一个元素设为null。这样是为了方便GC回收。
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
(十) 在ArrayList的增、删、改、查中,什么地方会修改modCount?
增如果导致扩容,则会修改modCount;删一定会修改modCount;改和查一定不会修改modCount。
(十一) ArrayList的时间复杂度是多少?
当修改、查询或者只在数组末尾增、删时,时间复杂度为O(1);对指定位置的元素进行增、删时,时间复杂度为O(n)
(十二)为什么ArrayList在增、删的时候效率低?
因为在增、删的过程中会涉及到数组的复制,效率低。
方法详解
源码就不一一展示了 最下面都有 大家可以对应一个一个的看
1、add(Object element): 向列表的尾部添加指定的元素。
2、size(): 返回列表中的元素个数。
3、get(int index): 返回列表中指定位置的元素,index从0开始。
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>(); //<String>泛型表示集合中存的是字符串形式的元素。
list.add("JSU"); //add()用于向List集合容器中添加元素。
list.add("ccw");
System.out.println(list);
System.out.println(list.size()); //size()用于获取集合中有多少个元素。
System.out.println(list.get(1)); //get()获取指定索引(从0开始)位置的元素。
}
}
4、add(int index, Object element): 在列表的指定位置插入指定元素。
import java.util.ArrayList;
import java.util.ArrayList;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("jsu");
list.add("ccw");
System.out.println(list);
list.add(1, "CCW"); //在指定位置添加元素,原来位置的元素后置。
System.out.println(list);
}
}
5、set(int i, Object element): 将索引i位置元素替换为元素element并返回被替换的元素。
import java.util.ArrayList;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("JSU");
list.add("ccw");
System.out.println(list);
list.set(1, "LEO"); //替换指定位置的元素,从0开始,替换了“ccw”。
System.out.println(list);
}
}
6、clear(): 从列表中移除所有元素。
7、isEmpty(): 判断列表是否包含元素,不包含元素则返回 true,否则返回false。
import java.util.ArrayList;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("JSU");
list.add("ccw");
System.out.println(list.isEmpty()); //集合容器没有元素,则true。
System.out.println(list);
list.clear(); //清空List集合中的所有元素。
System.out.println(list.isEmpty()); //集合容器没有元素,则true。
System.out.println(list);
}
}
8、contains(Object o): 如果列表包含指定的元素,则返回 true。
import java.util.ArrayList;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("JSU");
list.add("ccw");
boolean flag = list.contains("ccw"); //用来判断集合容器中是否含有参数元素。
System.out.println(flag);
}
}
这个方法需要思考一下,因为contains的参数类型是Object型,看一下源代码:
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
即list为上转型对象,使用String类的equals方法比较的是两个元素的内容是否相同
9、remove(int index): 移除列表中指定位置的元素,并返回被删元素。
import java.util.ArrayList;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("JSU");
list.add("ccw");
list.add("LEO");
System.out.println(list);
System.out.println(list.remove(1)); //删除指定索引(从0开始)位置的元素,并将元素返回,并后面元素前移。
System.out.println(list);
}
}
10、remove(Object o): 移除集合中第一次出现的指定元素,移除成功返回true,否则返回false。
import java.util.ArrayList;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("JSU");
list.add("ccw");
list.add("LEO");
System.out.println(list);
System.out.println(list.remove("LEO")); //删除指定索引(从0开始)位置的元素,并将元素返回,并后面元素前移。
System.out.println(list);
}
}
11、iterator(): 返回按适当顺序在列表的元素上进行迭代的迭代器。
import java.util.ArrayList;
import java.util.Iterator;
class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("JSU");
list.add("ccw");
list.add("LEO");
Iterator<String> ite = list.iterator(); //将List集合中元素转到iterator变量中。
while(ite.hasNext()) //hasNext()判断当前“指针”下面是否还有元素的方法,java中没有指针,这只是举个例子。
{
System.out.println(ite.next()); //如果“指针”下面有元素,则移动“指针”并获取相应位置的元素。
}
}
}
这里的许多源码都需要去源码的父类才能看到
源码
package java.util;
public class ArrayListextends AbstractList
implements List, RandomAccess,
Cloneable, java.io.Serializable {
// 序列版本号
private static final
long serialVersionUID = 8683452581122892189L;
// ArrayList基于该数组实现,用该数组保存数据
private transient Object[] elementData;
// ArrayList中实际数据的数量
private int size;
// 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 c) {
elementData = c.toArray();
size = elementData.length;
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
// 将当前容量值设为实际元素个数
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
// 确定ArrarList的容量。
// 若ArrayList的容量不足以容纳当前的全部元素,设置
// 新的容量=“(原始容量x3)/2 + 1”
public void ensureCapacity(int minCapacity) {
// 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的
modCount++;
int oldCapacity = elementData.length;
// 若当前容量不足以容纳当前的元素个数,
// 设置 新的容量=“(原始容量x3)/2 + 1”
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
//如果还不够,则直接将minCapacity设置为当前容量
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
// 添加元素e
public boolean add(E e) {
// 确定ArrayList的容量大小
ensureCapacity(size + 1); // Increments modCount!!
// 添加e到ArrayList中
elementData[size++] = e;
return true;
}
// 返回ArrayList的实际大小
public int size() {
return size;
}
// ArrayList是否包含Object(o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
//返回ArrayList是否为空
public boolean isEmpty() {
return size == 0;
}
// 正向查找,返回元素的索引值
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
// 反向查找(从数组末尾向开始查找),返回元素(o)的索引值
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
// 返回ArrayList的Object数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
// 返回ArrayList元素组成的数组
publicT[] toArray(T[] a) {
// 若数组a的大小 < ArrayList的元素个数;
// 则新建一个T[]数组,数组大小是“ArrayList的元素个数”,
// 并将“ArrayList”全部拷贝到新数组中
if (a.length < size)
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
// 若数组a的大小 >= ArrayList的元素个数;
// 则将ArrayList的全部元素都拷贝到数组a中。
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
// 获取index位置的元素值
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
// 设置index位置的值为element
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
// 将e添加到ArrayList中
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// 将e添加到ArrayList的指定位置
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
// 删除ArrayList指定位置的元素
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
// 删除ArrayList的指定元素
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
// 快速删除第index个元素
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
// 从"index+1"开始,用后面的元素替换前面的元素。
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 将最后一个元素设为null
elementData[--size] = null; // Let gc do its work
}
// 删除元素
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
// 便利ArrayList,找到“元素o”,则删除,并返回true。
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
// 清空ArrayList,将全部的元素设为null
public void clear() {
modCount++;
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
// 将集合c追加到ArrayList中
public boolean addAll(Collection c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
// 从index位置开始,将集合c添加到ArrayList
public boolean addAll(int index, Collection c) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + size);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
// 删除fromIndex到toIndex之间的全部元素。
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// Let gc do its work
int newSize = size - (toIndex-fromIndex);
while (size != newSize)
elementData[--size] = null;
}
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
}
// 克隆函数
public Object clone() {
try {
ArrayListv = (ArrayList) super.clone();
// 将当前ArrayList的全部元素拷贝到v中
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
// java.io.Serializable的写入函数
// 将ArrayList的“容量,所有的元素值”都写入到输出流中
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// 写入“数组的容量”
s.writeInt(elementData.length);
// 写入“数组的每一个元素”
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
// java.io.Serializable的读取函数:根据写入方式读出
// 先将ArrayList的“容量”读出,然后将“所有的元素值”读出
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// 从输入流中读取ArrayList的“容量”
int arrayLength = s.readInt();
Object[] a = elementData = new Object[arrayLength];
// 从输入流中将“所有的元素值”读出
for (int i=0; i<size; i++)
a[i] = s.readObject();
}
}
今天就写到这了 文章里面应该还有许多问题 稍后再来优化。