目录
1.简介
2.ArrayList的使用
(1)如何实例化ArrayList?(如何创建?)
(2)如何构造使用?
(3)为什么ArrayList的无参构造可以添加数据
(4)ArrayList常见操作
(5)ArrayList如何遍历
(6)ArrayList的扩容机制
1.简介
ArrayList背后是一个顺序表,顺序表底层是一个数组
- ArrayList是以泛型方式实现的,使用时必须要先实例化
- ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
- ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
- ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者 CopyOnWriteArrayList
- ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
2.ArrayList的使用
(1)如何实例化ArrayList?(如何创建?)
import java.util.ArrayList;
import java.util.List;
public class Test {
ArrayList<Integer> arrayList = new ArrayList<>();
List<Integer> list = new ArrayList<>();
}
有两种方法,区别:list当中的方法相比arraylist较少
(2)如何构造使用?
Array()
无参ArrayList()的原码:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
DEFAULTCAPACITY_EMPTY_ELEMENTDATA的原码:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
说明:常量数组,长度为0
elementDate的原码:
transient Object[] elementData
说明:element在此处只是一个数组引用,没有进行内存分配
总结:ArrayList的无参构造方法,并没有给数组分配大小,数组长度为0
ArrayList(int initialCapacity)
ArrayList(int initialCapacity) 原码:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
说明:传入的值为几,该方法就会给你分配多大的空间
EMPTY_ELEMENTDATA原码:
private static final Object[] EMPTY_ELEMENTDATA = {};
说明:如果传入的值为0时,就会创建一个空数组
说明:当传入负数时就会抛出异常
总结:传入的值就是分配给数组的空间,值为0就是空数组,值为负数则抛出异常
ArrayList(Collection <? extends E>c)
ArrayList(Collection <? extends E>c) 原码:
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
说明:
?是E或E 的子类 实现了Collection接口 满足这两种情况即可进行传递
此处arraylist的泛型类型是arraylist3泛型类型的本身,且实现了Collection接口所以可以进行传递
总结:?是E或E 的子类 实现了Collection接口 满足这两种情况即可进行传递
(3)为什么ArrayList的无参构造可以添加数据
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
add(E e)原码:
说明:把10传进去。此时e为10 ,size为0,elementDate是一个空数组
add(E e, Object[] elementData, int s)原码:
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
说明:传入的e为10,空数组,s为0;s==0再调用grow()
grow()原码:
private Object[] grow() {
return grow(size + 1);
}
grow(size + 1)原码:
说明:oldCapaticity为0不进入if语句,直接执行else语句,此处返回的是大小为10的数组
当我们出现执行if语句的情况时,会将原数组空间扩容为原来的1.5倍
总结:当调用不带参数的构造方法进行add的时候,第一次add会分配大小为10的内存
(4)ArrayList常见操作
remove :删除元素
有两种操作形式:
- 输入下标删除对应下标的值 E remove(int index)
- 输入对象直接删除值 boolean remove (Object o)
arrayList.remove(1);//删除1下标的12
arrayList.remove(new Integer(12));//删除12
arrayList.remove(Integer.valueOf(12)));//删除12
addAll(Collection<? extends E> c) :一组数据一次性添加,尾插 c 中的元素
?是E或E 的子类 实现了Collection接口 满足这两种情况即可进行传递
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(12);
ArrayList<Integer> arrayList1 = new ArrayList<>();
arrayList1.addAll(arrayList);
System.out.println(arrayList1);
List subList(int fromIndex, int toIndex) :截取部分 list,[ )左闭右开
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(12);
arrayList.add(23);
arrayList.add(34);
List<Integer> list = arrayList.subList(1,3);
System.out.println(list);
该方法是在arraylist的基础上截取的,并没有生成新的对象。
E set(int index, Eelement) :用指定的元素(可选操作)替换此列表中指定位置的元素。
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(12);
arrayList.add(23);
arrayList.add(34);
List<Integer> list = arrayList.subList(1,3);
arrayList.set(1,99);//1下标更新为99
System.out.println(list);
System.out.println(arrayList);
(5)ArrayList如何遍历
ArrayList 可以使用三方方式遍历:for循环+下标、foreach、使用迭代器
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(12);
arrayList.add(23);
arrayList.add(34);
for (int i = 0; i < arrayList.size(); i++) {
System.out.print(arrayList.get(i) + " ");
}
System.out.println();
for (Integer integer:arrayList) {
System.out.print(integer + " ");
}
System.out.println();
Iterator<Integer> iterator = arrayList.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
}
(6)ArrayList的扩容机制
ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。
此处跟上面无参构造添加数据的情况基本一致,只不过最后执行的是if语句:
总结:
- 检测是否真正需要扩容,如果是调用grow准备扩容
- 预估需要库容的大小
初步预估按照1.5倍大小扩容
如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
真正扩容之前检测是否能扩容成功,防止太大导致扩容失败- 使用copyOf进行扩容