一、ArrayList的父类
Arraylist是集合的一部分,它的根本父类是Collection,所以在说Arraylist之前我们浅说一下集合,集合和数组有很大的区别
数组 | 集合 | |
---|---|---|
长度 | 定长,不能改变 | 不定长 |
存储的数据类型 | 只能存一种, 能存储基本类型和引用类型 | 可以存多种数据类型; 只能存储引用类型 |
属性和方法 | 只有一个属性length,没有方法 | 提供了属性,以及方法 |
插入顺序和遍历顺序 | 有顺序,插入和遍历顺序一致 | 有的集合有序 有的集合无序 有的集合会排序 |
允许重复元素 | 允许重复 | 有的集合允许重复 有的集合不允许重复 |
集合的体系结构图
1、Collection
Collection是集合层级的根接口
里面定义了后续子类中需要使用的一些共有方法
但是因为是接口,无法演示,但是它有两个常用的子接口
List
Set
2、List
List集合,是Collection的子接口
List集合,保证有序,且允许重复元素的集合
List集合,能通过下标对数据进行精准控制(通过下标对数据进行增删改查)
List集合是接口,无法直接使用,但是它有两个常用的实现类
ArrayList
LinkedList
二、ArrayList
2.1 介绍
ArrayList是List实现类,即ArrayList也是允许存储重复元素,且保证顺序(插入和遍历顺序一致)
ArrayList也可以通过下标来操作数组
ArrayList底层是数组
ArrayList是不保证线程安全的,即不同步
2.2 演示API(共用方法)
private static void show1() {
ArrayList list = new ArrayList();// 创建了一个集合对象
// 向集合中添加1个元素(只能存储对象)
list.add(5);
list.add(2);
list.add(2);
list.add(3);
list.add(3);
list.add(1);
list.add(4);
// 存储的元素有序,且允许重复
System.out.println(list );
// addAll(Collection c),将集合中的所有元素添加到该集合中
ArrayList list2 = new ArrayList();
list2.add(11);
list2.add(22);
list2.add(33);
ArrayList list3 = new ArrayList();
list3.add(44);
list3.add(55);
list3.add(66);
System.out.println(list3 );
list3.addAll(list2);
System.out.println(list3 );
// 判断是否包含该元素
System.out.println(list3.contains(1));
System.out.println(list3.containsAll(list2));
// 移除元素
Integer i = 11;
list3.remove(i);
System.out.println(list3 );
ArrayList list4 = new ArrayList();
list4.add(33);
list4.add(55);
// list3.removeAll(list4); // 指定移除多个
list3.retainAll(list4);// 指定保留多个
System.out.println(list3 );
// 集合大小(元素个数)
System.out.println(list3.size( ));
// 是否为空
System.out.println(list3.isEmpty( ));
// 清空集合
list3.clear();
// 是否为空
System.out.println(list3.isEmpty( ));
}
2.3 演示API(关于下标操作)
ArrayList是基于数组实现,是能通过下标精准操作数据的
private static void show2() {
ArrayList list = new ArrayList( );
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println("list = " + list);
// add(int index,Object o)
// 在指定下标插入数据
list.add(2,5);
System.out.println("list = " + list);
// set(int index,Object o)
// 修改/设置指定下标的值
list.set(2,50);
System.out.println("list = " + list);
// Object get(int index)
Object o = list.get(2);
System.out.println("o = " + o);
// remove(int index)或者remove(object o)
list.remove(2);
System.out.println("list = " + list);
// subList(x,y)截取集合中的元素,左闭右开
List l2 = list.subList(1, 3);
System.out.println("l2 = " + l2);
}
三、集合迭代
迭代,即遍历
Collection顶层父接口中提供了一个Iterator接口可以运行迭代集合
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>( );
list.add(5);
list.add(3);
list.add(2);
list.add(1);
list.add(4);
// 获得迭代器
Iterator<Integer> iterator = list.iterator( );
while (iterator.hasNext()){// 判断有无下一个
Integer i = iterator.next( );// 取出下个
System.out.println(i );
}
// 一般上面的迭代器,可以简化成foreach,又叫增强for循环
// :左边是遍历得到的结果变量,右边是要遍历的集合或者是数组
for(Integer i : list) {
System.out.println(i );
}
int[] arr = {1,2,3,4,5};
for (int i:arr){
System.out.println(i);
}
}
四、ArrayList底层原理
ArrayList是有序,允许重复 ---> 是因为,底层是使用数组实现的
当new ArrayList时,默认创建了长度为0的数组
当第一次add的时候,创建了一个容量为10的数组
当添加到第11位时,要扩容,成原来的1.5倍
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 最初长度为0
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //DEFAULTCAPACITY_EMPTY_ELEMENTDATA默认为空
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity); //如果最小容量减去原来的对象长度大于零,说明容量已经不够了,就需要进行扩容
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容到原来的1.5倍
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);
}
解释如下(来自通义灵码)
这些函数是Java集合框架中ArrayList类的内部方法,用于确保ArrayList具有足够的容量来添加新元素。 ensureCapacityInternal(int minCapacity) 方法: 检查当前ArrayList的容量是否足够,如果不够则调用 ensureExplicitCapacity(minCapacity) 方法来确保容量足够。 ensureExplicitCapacity(int minCapacity) 方法: 增加modCount,用于记录ArrayList的结构修改次数。 如果所需的最小容量大于当前数组长度,则调用 grow(minCapacity) 方法来增加数组容量。 grow(int minCapacity) 方法: 计算新的容量大小,通常是当前容量的1.5倍。 如果新的容量小于所需的最小容量,则将新的容量设置为所需的最小容量。 如果新的容量超过最大数组大小,则调用 hugeCapacity(minCapacity) 方法来处理。 最后,使用Arrays.copyOf方法创建一个新的数组,容量为新的容量,并将当前元素数据复制到新数组中。 这些方法的目的是为了确保ArrayList在添加新元素时能够有足够的空间,如果空间不足,则会增加容量,以避免频繁地重新分配内存。