ArrayList(List接口的实现类)

ArrayList注意事项

  • 可以存储空值,但是遍历会出错
  • ArrayList存储数据底层由数组来实现
  • ArrayList基本等同于Vector,但是ArrayList是线程不安全的,多线程不建议使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class Test {
public static void main(String [] args){

Dog dog1=new Dog("ahhua",12);
Dog dog2=new Dog("a",15);
Dog dog3=new Dog("ah",13);
Dog dog4=new Dog("ah",13);

List list=new ArrayList();
list.add(dog2);
list.add(dog1);
list.add(dog2);
list.add(null);
for (Object o :list) {
//可以存储,但是不可以遍历
System.out.println(o.toString());
}



}
}
class Dog{
private String name;
private int age;

public Dog(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

image-20220615102549866

ArrayList的底层结构和源码分析

无参构造器的扩容

首先我们运行以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class Test {
public static void main(String [] args){
//先调用ArrayList的无参构造其
ArrayList arrayList=new ArrayList();
//第一个for不扩容,<=10
for (int i=0;i<=10;i++){
arrayList.add(i);
}
//第二个for扩容,已经大于默认的10
for (int i=11;i<15;i++){
arrayList.add(i);
}


}
}

但我们调用无参构造器时,调用了以下方法,并且定义的类型为Object[]数组类型,我们可以确认ArrayList的底层使用的是数组存储

image-20220615102633892

image-20220615102641148

我们可以看到在运行到add方法时,进入到了一个boolean的方法,此方法先决定是否要进行扩容,而add方法的第一行的函数如下一张图

image-20220615102658151

首先判断该存储的数组是否为空,如果为空,则进行比较,并且选取两个数的一个最大数作为初始集合的大小,应该为10。而该方法的最后一行的代码,则是确定是否还进行底层扩容,大于minCapacity则进行扩容。

image-20220615102758224

当我们决定扩容时,则调用下面的函数,扩容为原来的1.5倍,而copyof方法会保持地址不变,直接增加数。

image-20220615102827255

当我们运行之后

image-20220615102840971

15个空间不够时,我们许需要扩容,扩容之后

image-20220615102850520

其实在这个过程中进行扩容这么大,是因为在这个arraylist添加和删除的过程中,成本比较大,每一次添加个删除都要不可避免的移动元素,保证空间的连续性,每一次大小变为原来的两倍,避免不得不再一次改变容量

有参构造器

有参构造器,我们可以给他附上初始值,而每一次扩容依然是原来的1.5倍,运行的原理和上面的一样,只是初始值为我们赋值的那个数,而不是10.