本篇文章将对ArrayList类进行讲解



一、ArrayList类介绍

上篇文章我们对顺序表的增删查改等方法进行了模拟实现,实际上Java提供了ArrayList类,而在这个类中就包含了顺序表的一系列方法,这样在用顺序表解决问题时就不用每次都去实现它的方法了

再ArrayList类中有下面几个字段:

上述字段会在下面的解释中进行讲解

二、ArrayList的构造方法

ArrayList的构造方法一共有三种

2.1 第一种构造方法

上述代码中,先定义了数组EMPTY_ELEMENTDATA,该数组为空,之后又定义了数组elementData,接下来红色框部分的就是构造方法,该方法有一个参数initialCapacity(即顺序表的初始容量),当initialCapacity > 0时,为elementData分配了长度为initialCapacity大小的空间,当initialCapacity =0时,将elementData赋值为EMPTY_ELEMENTDATA,也就是此时elementData为空数组,即顺序表现在为空,若initialCapacity为负数,则抛出异常

总结:该构造方法就是给顺序表分配空间的

ArrayList arrayList = new ArrayList(5); //此时顺序表的长度为5arrayList.add(1);arrayList.add(2);arrayList.add(3);

2.2 第二种构造方法

可以看到此时elementData为一个空数组,那么看下面的代码

ArrayList arrayList = new ArrayList();arrayList.add(1);arrayList.add(2);arrayList.add(3);

构造方法并没有给顺序表分配空间,为什么此代码编译运行都没有问题?下面通过源码进行解释,首先不带参的构造方法确实没有给顺序表分配空间,那么没有报错的原因只可能是在add方法上

add方法中调用了ensureCapacityInternal方法:

在该方法中调用了ensureExplicitCapacity方法,其参数为calculateCapacity方法的返回值,该方法的参数分别为elementData数组和minCapacity先看calculateCapacity方法:

上述代码中的DEFAULT_CAPACITY是默认容量:10,minCapacity为1,所以这里将10作为该方法的返回值并作为ensureExplicitCapacity的参数,再去看ensureExplicitCapacity方法:

接下来看grow方法:

总结:

1.对于空的顺序表,第一个add方法会进行扩容,将顺序表的扩容为默认容量10

2.add方法的扩容是按照1.5倍扩容的

2.3 第三种构造方法

该构造方法的参数部分:

Collection

三、ArrayList的一些方法

ArrayList类提供的方法大部分和上篇文章中模拟实现的方法一致,这里讲解一些没有模拟实现的方法:

1. boolean addAll(Collection c)

该方法为将一个顺序表的所有元素尾插到另一个顺序表:

public static void main(String[] args) {ArrayList arrayList = new ArrayList();arrayList.add(1);arrayList.add(2);ArrayList list = new ArrayList();list.add(3);list.addAll(arrayList);System.out.println(list); //结果为 [3, 1, 2]}

2. E remove(int index)

删除index位置的元素:

public static void main(String[] args) {ArrayList arrayList = new ArrayList();arrayList.add(1);arrayList.add(2);arrayList.remove(0);System.out.println(arrayList); //结果为 [2]}

3. List subList(int fromIndex, int toIndex)

左闭右开的区间截取顺序表中从fromIndextoIndex的元素,注意:这里的截取并不是指向一个新的对象,它依然指向原来的对象

public static void main(String[] args) {ArrayList arrayList = new ArrayList();arrayList.add(1);arrayList.add(2);arrayList.add(3);List list = arrayList.subList(0, 2);//list依然指向原来的对象System.out.println(list); //结果为 [1, 2]list.set(0, 100);System.out.println(list); //[100, 2]System.out.println(arrayList); //[100, 1, 2]}

四、ArrayList的遍历

先创建一个顺序表:

ArrayList arrayList = new ArrayList();arrayList.add(1);arrayList.add(2);arrayList.add(3);

4.1 for循环

for (int i = 0; i < arrayList.size(); i++) {System.out.print(arrayList.get(i) +" ");}

4.2 for-each循环

for(Integer x : arrayList) { //:左边为顺序表中元素的类型+变量System.out.print(x +" ");}

4.3 迭代器

1.Iterator接口中iterator()方法

Iterator it = arrayList.iterator();while(it.hasNext()) { System.out.print(it.next() +" ");//判断是否有下一个元素,如果有则打印下一个元素,并将it指向下一个元素}

2.ListIterator接口中listIterator()方法

ListIterator接口继承了Iterator接口,也可以作为迭代器遍历ArrayList

ListIterator it1 = arrayList.listIterator();while(it1.hasNext()) {System.out.print(it1.next() +" ");}

3.利用迭代器从后往前打印

ListIterator it2 = arrayList.listIterator(arrayList.size());//这里要将顺序表的长度作为参数传过去while(it2.hasPrevious()) {System.out.print(it2.previous() +" ");//判断是否有前一个元素,如果有则打印前一个元素,并将it指向前一个元素}

本篇文章到此结束,下篇文章会对链表相关知识进行讲解