ArrayList API 最清晰使用大全
说到ArrayList,大家一定都不陌生。作为java中常用的集合之一,ArrayList在平常的刷题以及面试中屡见不鲜,其重要性可见一斑。
ArrayList底层用数组实现,继承了一个抽象类AbstractList,实现了四个接口List、RandomAccess, Cloneable, java.io.Serializable。
相信ArrayList的原理大家都十分熟悉,毕竟网上博客一搜一大把,而且基本一样(。・ω・。),在这里我就不多bb了。
本文主要介绍ArrayList各种API的功能以及具体使用方法,保证让你一眼就会,一下就懂
好了,废话不多说,上图!!
如上图所示,一共15种方法(加上多态可能有二三十种),常用的在左边,不常用的在右边,整体遵循男左女右的原则。
接下来,我将从构造方法开始,以逆时针方向依次介绍各个方法。
1. ArrayList()
1.1ArrayList()
不带参数的构造方法。直接构造一个容量为10的数组来存数据。
说到容量,就不得不说一下ArrayList的扩容机制。ArrayList的底层是用数组实现的,一旦数据的长度超过预先设定的数组长度,就会触发扩容机制。
扩容机制,将创建一个容量为以前数组1.5倍容量的新数组来存放所有的数据,至于为什么是1.5倍,大家有兴趣的可以去看ArrayList的源码。其中,grow()函数详细解释了扩容的整个过程。
值得一提的是,ArrayList在使用不带参的构造方法时,虽然默认容量是10,但第一时间容量为0。只有当调用add()方法往ArrayList中插入第一个元素,也就是ArrayList中存在元素时,容量才会变为10。
public class MyArrayList {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
System.out.println("调用add()之前list容量为:"+getArrayListCapacity(list));
list.add(52);
System.out.println("调用add()之后list容量为:"+getArrayListCapacity(list));
for (int i = 0; i <10 ; i++) {
list.add(i);
if (i == 8)
System.out.println("list中有是"+list.size()+"个元素。"+"当前list容量为"+getArrayListCapacity(list));
if(i == 9)
System.out.println("list中有是"+list.size()+"个元素。"+"当前list容量为"+getArrayListCapacity(list));
}
}
public static int getArrayListCapacity(ArrayList<?> arrayList) {
Class<ArrayList> arrayListClass = ArrayList.class;
try {
//获取 elementData 字段
Field field = arrayListClass.getDeclaredField("elementData");
//开始访问权限
field.setAccessible(true);
//把示例传入get,获取实例字段elementData的值
Object[] objects = (Object[])field.get(arrayList);
//返回当前ArrayList实例的容量值
return objects.length;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
}
1.2 ArrayList(int initialCapacity)
带参数的构造方法:参数为初始容量,一旦使用这种声明方法, 无论List中有无元素,初始容量都为设定值。
ArrayList<Integer> list = new ArrayList<>(5);
System.out.println("调用add()方法之前List的容量为"+getArrayListCapacity(list));
list.add(1);
System.out.println("调用add()方法之后List的容量为"+getArrayListCapacity(list));
1.3ArrayList(Collection<> c)
带参构造方法:参数为一个集合,及将该集合的元素加入新创建的List中去。
注意:使用这种构造方法时,新创建的List容量为传入集合的大小,并不会初始化为10,再添加新的元素时按扩容机制进行扩容。
List<Integer> list1 = new ArrayList<>();
for (int i = 0; i <5 ; i++) {
list1.add(i);
}
ArrayList<Integer> list = new ArrayList<>(list1);
System.out.println(list);
System.out.println("调用add()方法之前List的容量为"+getArrayListCapacity(list));
list.add(6);
System.out.println("调用add()方法之后List的容量为"+getArrayListCapacity(list));
2. add()
2.1 add(E e)
往list尾部添加一个元素,这个前面代码中有用到,不多做介绍。函数返回类型为blooean,添加成功则返回true。
2.2 add(int index, E e)
往指定位置添加元素。该函数没有返回值。
List<Integer> list1 = new ArrayList<>();
for (int i = 0; i <5 ; i++) {
list1.add(i);
}
System.out.println(list1);
list1.add(1,10);
System.out.println(list1);
2.3 addAll(Collection c)
效果与add(E e)类似,只不过添加的是整个集合中的元素。函数返回类型为blooean,添加成功则返回true。
2.4 addAll(int index, Collection c)
往指定位置之后添加整个集合的元素。函数返回类型为blooean,添加成功则返回true。
List<Integer> list = new ArrayList<>();
for (int i = 0; i <5 ; i++) {
list.add(i);
}
List<Integer> list1 = new ArrayList<>();
list1.add(12);
list1.add(55);
list1.add(13);
System.out.println(list1);
list1.addAll(1,list);
System.out.println(list1);
3. get()
get(int index):获取特定位置的元素。比较简单,不多做描述。
4. set()
set(int index , E e):将特定位置的元素更改为e。
List<Integer> list1 = new ArrayList<>();
list1.add(12);
list1.add(55);
list1.add(13);
System.out.println(list1);
list1.set(2,20);
System.out.println(list1);
5. remove()
5.1 remove(int index)
移除指定位置的元素,并返回该元素。
5.2 remove(Object c)
移除某个特定的元素,返回类型为boolean。注意输入参数只能是对象,当直接输入int类型时,默认为索引。
5.3 removeAll(Collection c)
移除指定集合中的所有元素。返回类型为boolean类型。与之相对的是retainAll(Collection c),两者功能类似,本文不多做讨论。
List<Integer> list = new ArrayList<>();
for (int i = 0; i <11 ; i++) {
list.add(i*i);
}
System.out.println("当前list集合为:"+list);
int num = list.remove(5);
System.out.println("移除下标为5的元素值:"+num);
System.out.println("当前list集合为:"+list);
Integer integer = 81;
list.remove(integer);
System.out.println("移除81后,list集合为:"+list);
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(4);
System.out.println("list1集合中的元素为:"+list1);
list.removeAll(list1);
System.out.println("移除list1集合元素后,list集合元素为:"+list);
6. indexOf()
indexOf(Object c):找到指定元素第一次出现的下标并返回,找到了则返回下标,否则返回-1。
示例程序与LastIndexOf一起。
7. LastIndexOf()
LastIndexOf(Object c):找到元素最后一次出现的下标并返回,找到了则返回下标,否则返回-1。
List<Integer> list = new ArrayList<>();
for (int i = 0; i <11 ; i++) {
list.add(i*i);
}
list.add(9);
list.add(9);
System.out.println("当前list集合为:"+list);
int num = list.indexOf(9);
System.out.println("元素9第一次出现的位置为:"+num);
int num1 = list.indexOf(5);
System.out.println("元素5第一次出现的位置为:"+num1);
int num2 = list.lastIndexOf(9);
System.out.println("元素9最后一次出现的位置为:"+num2);
8. trimTosize()
trimTosize():英文中trim有修剪,切去的意思。根据字面意思也能理解,该函数有去掉多余空间的意思。
因为ArrayList的扩容机制,底层数组的容量一般会有多余。所以一般当内存不够时,就会调用trimTosize()去掉多余的空间。
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i <11 ; i++) {
list.add(i*i);
}
System.out.printf("当前list中有%d个元素\n",list.size());
System.out.println("当前list容量为:"+getArrayListCapacity(list));
list.trimToSize();
System.out.println("使用trimToSize()之后,list容量为:"+getArrayListCapacity(list));
list.add(1);
System.out.println("扩容后list容量为:"+getArrayListCapacity(list));
9. ensureCapacity()
ensureCapacity(int minCapacity):手动扩容。
由于ArrayList每次扩容时,都需要去判断数据是够超过容量。当数据量较大,又没有初始化容量时,判断次数大大增多,消耗性能。而ensureCapacity相当于提前告诉了程序需要扩容的 大小,可以提高性能。
int N = 1000000;
ArrayList<Integer> list = new ArrayList<>();
long startTime = System.currentTimeMillis();
for (int i = 0; i <N ; i++) {
list.add(i);
}
long endTime = System.currentTimeMillis();
System.out.println("没有使用ensureCapacity时,程序运行时间为:"+(endTime-startTime)+"ms");
ArrayList<Integer> list1 = new ArrayList<>();
list.ensureCapacity(N);
long startTime1 = System.currentTimeMillis();
for (int i = 0; i <N ; i++) {
list1.add(i);
}
long endTime1 = System.currentTimeMillis();
System.out.println("使用ensureCapacity后,程序运行时间为:"+(endTime1-startTime1)+"ms");
10. clear()
clear():清空list中元素,没有返回值。
这个比较简单,不过值得一提的是,尽管list中元素清空了,但容量还是没变。也就是说申请的内存并不会被释放,至于什么时候去释放,这就是JVM去干的事情了。
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i <12 ; i++) {
list.add(i);
}
System.out.println(list);
System.out.println("使用clear之前容量大小为:"+getArrayListCapacity(list));
list.clear();
System.out.println("使用clear之后容量大小为:"+getArrayListCapacity(list));
11. clone()
clone():复制一个ArrayList,传到新的list中。
新list的容量并不等于原list的容量,而是等于原数组中元素数量。相当于在原list的基础上用了一次trimToSize()。
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i <12 ; i++) {
list.add(i);
}
System.out.println(list);
ArrayList<Integer> list1 = (ArrayList<Integer>) list.clone();
System.out.println("list的容量为:"+getArrayListCapacity(list));
System.out.println(list1);
System.out.println("list1的容量为:"+getArrayListCapacity(list1));
12.contains()
contains(Object o):判断list中是否包含目标对象,包含则返回true。
这个比较简单,就不举例了。
13. subList()
subList(int fromIndex, int toIndex):从list取出指定范围内的元素组成新的list,遵循左闭右开原则。
比如(1,5)就是取出下标为1,2,3,4的四个元素。
List<Integer> list = new ArrayList<>();
for (int i = 0; i <12 ; i++) {
list.add(i);
}
List<Integer> list1 = list.subList(1,5);
System.out.println("list中元素为:"+list);
System.out.println("list中(1,5)的元素为:"+list1);
14. isEmpty()
isEmpty():判断list是否为空,空则返回true。
15. size()
size():返回list中实际元素的个数。
都是看源码还有博客自己学的,大概就这么多东西了,有什么错误的地方欢迎批评指正~( ・´ω`・ )。