*/
transient Object[] elementData; // non-private to simplify nested class access
/**
-
The size of the ArrayList (the number of elements it contains).
-
集合中元素的个数
-
@serial
*/
private int size;
复制代码
-
DEFAULT_CAPACITY:集合的默认容量,默认为10,通过new ArrayList() 创建List集合实例时的默认容量是10。
-
EMPTY_ELEMENTDATA:空数组,通过new ArrayList(0) 创建List集合实例时用的是这个空数组。
-
DEFAULTCAPACITY_EMPTY_ELEMENTDATA:默认容量空数组,这种是通过new ArrayList()无参构造方法创建集合时用的是这个空数组,与EMPTY_ELEMENTDATA的区别是在添加第一个元素时使用这个空数组的会初始化为DEFAULT_CAPACITY(10)个元素。
-
elementData:存储数据元素的数组,使用transient修饰,该字段不被序列化。
-
size:存储数据元素的个数,elementData数组的长度并不是存储数据元素的个数。\
3.ArrayList 构造方法
- 有参构造 ArrayList(int initialCapacity)
/**
-
Constructs an empty list with the specified initial capacity.
-
构造具有指定初始容量的空数组
-
@param initialCapacity the initial capacity of the list 列表的初始容量
-
@throws IllegalArgumentException if the specified initial capacity is negative
-
传入初始容量,如果大于0就初始化elementData为对应大小,如果等于0就使用EMPTY_ELEMENTDATA空数组,
-
如果小于0抛出异常。
*/
// 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("不合理的初识容量: " +
initialCapacity);
}
}
复制代码
- 无参构造ArrayList()
/**
-
Constructs an empty list with an initial capacity of ten.
-
构造一个初始容量为10的空数组
-
不传初始容量,初始化为DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,
-
会在添加第一个元素的时候扩容为默认的大小,即10。
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
复制代码
- 有参构造ArrayList(Collection c)
/**
-
Constructs a list containing the elements of the specified
-
collection, in the order they are returned by the collection’s
-
iterator.
-
把传入集合的元素初始化到ArrayList中
-
@param c the collection whose elements are to be placed into this list
-
@throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
// 将构造方法中的集合参数转换成数组
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 检查c.toArray()返回的是不是Object[]类型,如果不是,重新拷贝成Object[].class类型
if (elementData.getClass() != Object[].class)
// 数组的创建与拷贝
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 如果c是空的集合,则初始化为空数组EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
}
}
复制代码
4. ArrayList 相关操作方法
添加操作
**1.add(E e)添加元素到集合中
添加元素到末尾,平均时间复杂度为O(1):**
/**
-
Appends the specified element to the end of this list.
-
添加元素到末尾,平均时间复杂度为O(1)
-
- @param e element to be appended to this list
-
@return true (as specified by {@link Collection#add})
*/
public boolean add(E e) {
// 每加入一个元素,minCapacity大小+1,并检查是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 把元素插入到最后一位
elementData[size++] = e;
return true;
}
// 计算最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果是空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 返回DEFAULT_CAPACITY 和 minCapacity的大一方
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// 检查是否需要扩容
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;// 数组结构被修改的次数+1
// overflow-conscious code 储存元素的数据长度小于需要的最小容量时
if (minCapacity - elementData.length > 0)
// 扩容
grow(minCapacity);
}
/**
-
扩容
-
Increases the capacity to ensure that it can hold at lea
-
number of elements specified by the minimum capacity arg
-
增加容量以确保它至少可以容纳最小容量参数指定的元素数量
-
@param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// 原来的容量
int oldCapacity = elementData.length;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新容量发现比需要的容量还小,则以需要的容量为准
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果新容量已经超过最大容量了,则使用最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 以新容量拷贝出来一个新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 使用最大容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
复制代码
执行流程:
-
检查是否需要扩容;
-
如果elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA则初始化容量大小为DEFAULT_CAPACITY;
-
新容量是老容量的1.5倍(oldCapacity + (oldCapacity >> 1)),如果加了这么多容量发现比需要的容量还小,则以需要的容量为准;
-
创建新容量的数组并把老数组拷贝到新数组;
**2.add(int index, E element)添加元素到指定位置
添加元素到指定位置,平均时间复杂度为O(n):**
/**
-
Inserts the specified element at the specified position in this
-
list. Shifts the element currently at that position (if any) and
-
any subsequent elements to the right (adds one to their indices).
-
添加元素到指定位置,平均时间复杂度为O(n)。
-
- @param index 指定元素要插入的索引
-
@param element 要插入的元素
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
// 检查是否越界
rangeCheckForAdd(index);
// 检查是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将inex及其之后的元素往后挪一位,则index位置处就空出来了
// 进行了size-索引index次操作
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 将元素插入到index的位置
elementData[index] = element;
// 元素数量增1
size++;
}
/**
-
A version of rangeCheck used by add and addAll.
-
add和addAll方法使用的rangeCheck版本
*/
// 检查是否越界
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
复制代码
执行流程:
-
检查索引是否越界;
-
检查是否需要扩容;
-
把插入索引位置后的元素都往后挪一位;
-
在插入索引位置放置插入的元素;
-
元素数量增1;
**3.addAll(Collection c)添加所有集合参数中的所有元素
求两个集合的并集:**
/**
-
Appends all of the elements in the specified collection to the end of
-
this list, in the order that they are returned by the
-
specified collection’s Iterator. The behavior of this operation is
-
undefined if the specified collection is modified while the operation
-
is in progress. (This implies that the behavior of this call is
-
undefined if the specified collection is this list, and this
-
list is nonempty.)
-
将集合c中所有元素添加到当前ArrayList中
-
- @param c collection containing elements to be added to this list
-
@return true if this list changed as a result of the call
-
@throws NullPointerException if the specified collection is null
*/
public boolean addAll(Collection<? extends E> c) {
// 将集合c转为数组
Object[] a = c.toArray();
int numNew = a.length;
// 检查是否需要扩容
ensureCapacityInternal(size + numNew); // Increments modCount
// 将c中元素全部拷贝到数组的最后
System.arraycopy(a, 0, elementData, size, numNew);
// 集合中元素的大小增加c的大小
size += numNew;
// 如果c不为空就返回true,否则返回false
return numNew != 0;
}
复制代码
执行流程:
-
拷贝c中的元素到数组a中;
-
检查是否需要扩容;
-
把数组a中的元素拷贝到elementData的尾部;
访问操作
**4.get(int index)获取指定索引位置的元素
获取指定索引位置的元素,时间复杂度为O(1)。**
/**
-
Returns the element at the specified position in this list.
-
- @param index index of the element to return
-
@return the element at the specified position in this list
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
// 检查是否越界
rangeCheck(index);
// 返回数组index位置的元素
return elementData(index);
}
/**
-
Checks if the given index is in range. If not, throws an appropriate
-
runtime exception. This method does not check if the index is
-
negative: It is always used immediately prior to an array access,
-
which throws an ArrayIndexOutOfBoundsException if index is negative.
-
检查给定的索引是否在集合有效元素数量范围内
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
@SuppressWarnings(“unchecked”)
E elementData(int index) {
return (E) elementData[index];
}
复制代码
执行流程:
-
检查索引是否越界,这里只检查是否越上界,如果越上界抛出IndexOutOfBoundsException异常,如果越下界抛出的是ArrayIndexOutOfBoundsException异常。
-
返回索引位置处的元素;
删除操作
5.remove(int index)删除指定索引位置的元素,
删除指定索引位置的元素,时间复杂度为O(n)。
/**
-
Removes the element at the specified position in this list.
-
Shifts any subsequent elements to the left (subtracts one from their
-
indices).
-
删除指定索引位置的元素,时间复杂度为O(n)。
-
- @param index the index of the element to be removed
-
@return the element that was removed from the list
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
// 检查是否越界
rangeCheck(index);
// 集合底层数组结构修改次数+1
modCount++;
// 获取index位置的元素
E oldValue = elementData(index);
int numMoved = size - index - 1;
// 如果index不是最后一位,则将index之后的元素往前挪一位
if (numMoved > 0)
// 进行了size-索引index-1次操作
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
// 将最后一个元素删除,帮助GC
elementData[–size] = null; // clear to let GC do its work
// 返回旧值
return oldValue;
}
复制代码
执行流程:
-
检查索引是否越界;
-
获取指定索引位置的元素;
-
如果删除的不是最后一位,则其它元素往前移一位;
-
将最后一位置为null,方便GC回收;
-
返回删除的元素。
注意:从源码中得出,ArrayList删除元素的时候并没有缩容。
**6.remove(Object o)删除指定元素值的元素
删除指定元素值的元素,时间复杂度为O(n)。**
/**
-
Removes the first occurrence of the specified element from this list,
-
if it is present. If the list does not contain the element, it is
-
unchanged. More formally, removes the element with the lowest index
-
i such that
-
(o==null ? get(i)==null : o.equals(get(i)))
-
(if such an element exists). Returns true if this list
-
contained the specified element (or equivalently, if this list
-
changed as a result of the call).
-
删除指定元素值的元素,时间复杂度为O(n)。
-
- @param o element to be removed from this list, if present
-
要从此列表中删除的元素(如果存在的话)
-
@return true if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
// 遍历整个数组,找到元素第一次出现的位置,并将其快速删除
for (int index = 0; index < size; index++)
// 如果要删除的元素为null,则以null进行比较,使用==
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
// 遍历整个数组,找到元素第一次出现的位置,并将其快速删除
for (int index = 0; index < size; index++)
// 如果要删除的元素不为null,则进行比较,使用equals()方法
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
-
Private remove method that skips bounds checking and does not
-
return the value removed.
-
专用的remove方法,跳过边界检查,并且不返回删除的值。
*/
private void fastRemove(int index) {
// 少了一个越界的检查
modCount++;
// 如果index不是最后一位,则将index之后的元素往前挪一位
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
// 将最后一个元素删除,帮助GC
elementData[–size] = null; // clear to let GC do its work
}
复制代码
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
针对以上面试题,小编已经把面试题+答案整理好了
面试专题
除了以上面试题+答案,小编同时还整理了微服务相关的实战文档也可以分享给大家学习
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
227)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
针对以上面试题,小编已经把面试题+答案整理好了
[外链图片转存中…(img-lEcwZC89-1712898998227)]
[外链图片转存中…(img-df8lv8F5-1712898998227)]
[外链图片转存中…(img-BAhRoMQP-1712898998227)]
面试专题
[外链图片转存中…(img-XLyXFbpD-1712898998228)]
除了以上面试题+答案,小编同时还整理了微服务相关的实战文档也可以分享给大家学习
[外链图片转存中…(img-6lLLiAx9-1712898998228)]
[外链图片转存中…(img-KufpWGKF-1712898998228)]
[外链图片转存中…(img-ecWPEWGo-1712898998228)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!