概述
1.定义
ArrayList是一个动态数组,也是我们常用的集合,它允许任何元素的插入,包括null。
ArrayList初始化容量为10,该容量代表了数组的大小,随着容器中容量的不断增加,容器的大小也会随着增加。在每次向容器中增加元素时,会进行容量检查,当快溢出时,会进行扩容操作。
ArrayList继承自 AbstractList,实现了 List 接口。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。
2.特征
1、ArrayList可以存放重复数据,也可以存放null值
2、ArrayList中元素存放和插入顺序一致,插入的元素是有序的
3、ArrayList集合底层采用的是动态数组来存储数据
4、动态扩容
5、非线程安全,异步
6、 擅长随机访问(get ,set)
3.1属性和默认值
//默认的初始容量10
private static final int DEFAULT_CAPACITY = 10;
//空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {};
//存储数据:使用的是数组,数组存储的数据类型是Object
private transient Object[] elementData;
//用来记录存放数据的个数
private int size;
ArrayList底层存储元素是使用数组
数组 elementData.length:表示当前数组容量,最大存储的数据个数
size:实际存放的数据个数
3.2构造函数
//有参构造函数:通过指定初始容量initialCapacity来实例化ArrayList
public ArrayList(int initialCapacity) {
super();
//参数合法性校验
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
//实例化一个大小为initialCapacity数组并将数组赋值给elementData
this.elementData = new Object[initialCapacity];
}
//无参构造函数 elementData赋值为空数组
public ArrayList() {
// ArrayList(DEFAULT_CAPACITY);
super();
this.elementData = EMPTY_ELEMENTDATA;
//将默认值的赋值在add中完成
}
//通过集合来实例化ArrayList
public ArrayList(Collection<? extends E> c) {
//将集合转化为数组,直接赋值给elementData
elementData = c.toArray();
//将集合中已有元素的带下赋值给size
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
3.3常用方法:
add(Object e)
add(int index ,Object e)
addAll(Collection c)
addAll(int index , Collection c)
size()
get(int index)
set(int index,Object e)
indexOf(Object c)
lastIndexOf(Object c)
isEmpty()
remove(int index)
remove(Object c)
removeAll(Collection<?> c)
contains(Object c)
containsAll(Collection<?> c)
clear()
clone()
iterator()
retainAll(Collection<?> c)
subList(int fromIndex,int toIndex)
trimToSize() 回收多余容量
toArray()
toArray(T[] a)
4.常见方法源码解析
(1)add:添加元素
ArrayList在未指定容量时,初始容量时10
modCount属性是版本控制器,也是ArrayList中的属性(继承自AbstractList中属性),和业务无关,仅仅是做版本控制,在集合进行变更时(修改、删除、添加)会自增1
扩容时机和扩容机制:当要插入数据的个数大于了数组容量,需要进行扩容,将容量大小变更为原大小的1.5倍,需要将原集合数据拷贝到新数组中
public boolean add(E e) {
//考虑扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//将数据通过数组坐标插入到数据尾部,并对size+1
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
//在添加第一个元素时,如果集合是通过无参构造实例时,会进入到if
//在未指定集合容量时,默认情况下数组初始化大小为10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//minCapacity(size+1) > elementData.length,意味着数组空间不足,扩容时机
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//扩容点
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容为原大小的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);//oldCapacity >> 1 => oldCapacity/2
//对newCapacity进行边界的校正(不能小于minCapacity,不能大于MAX_ARRAY_SIZE)
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将原有的集合数据拷贝到新容量为newCapacity的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
(2)get():获取元素
public E get(int index) {
//检查查询位置的合法性 index <size
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {
return (E) elementData[index];
}
(3)remove:删除元素
public boolean remove(Object o) {
//删除操作判断区分是否为null值,如果为null,判断相等使用== 如果不为null,判断相等使用equals
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
//删除操作
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
//将index位置之后的数据全部前移一位
System.arraycopy(elementData, index+1, elementData, index,numMoved);
//将最后一个位置置为null,并将size-1
elementData[--size] = null; // clear to let GC do its work
}
注:Arrays.copyof() 拷贝和System.arraycopy 异同点:
copyOf 方法 | arraycopy 方法 |
---|---|
调用时只需要原数组即可 | 调用时需要原数组和目标数组 |
有返回值 | 无返回值 |
新建一个对象,并调用arraycopy方法 | 底层方法 |
ArrayList和数组的区别?
1、ArrayList是可以动态扩容的,数组是不能(长度一旦确定是固定的)
2、存储数据类型不相同,数组可以存在基本类型、包装类型、自定义类型、而ArrayList只能存储基本类型和自定义类型
3、集合提供了丰富的API操作、无序关注内部处理细节、对于数组而言需要关注底层实现细节
最后
以上就是腼腆导师为你收集整理的ArrayList相关知识总结的全部内容,希望文章能够帮你解决ArrayList相关知识总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复