ArrayList源码分析(jdk11)
程序员文章站
2022-07-14 16:07:04
...
初始化方法:
private static final int DEFAULT_CAPACITY = 10;//默认初始容量
/**
* 用户指定容量为0时返回数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用户调用无参构造函数,在第一次添加元素时会以DEFAULT_CAPACITY扩容
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 保存数据,数组大小是arraylist的容量
* transient:表示对象序列化时不包括该数组(writeObject()和readObject()实现对数组序列化和反序列化)
* 原因:elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,
* 那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,
* 就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* arraylist中实际大小(保存数据数量)
*/
private int size;
/**
* 创建指定初始容量的空arraylist
*
* @param initialCapacity 初始容量
* @throws IllegalArgumentException 当初始容量小于0时抛异常
*/
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);
}
}
/**
* 无参构造函数,在第一次加入元素时扩容至默认容量
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 创建一个包含collection的ArrayList
* @param c 要放入 ArrayList 中的集合,其内元素将会全部添加到新建的 ArrayList 实例中
* @throws NullPointerException 当参数 c 为 null 时抛出异常
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();//将集合转为数组
if ((size = elementData.length) != 0) {//将数组长度赋值给size 并判断是否为0
if (elementData.getClass() != Object[].class)//如果数组不是objec[]t类型
elementData = Arrays.copyOf(elementData, size, Object[].class);//将数组拷贝到object[]数组
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
扩容方法:
/**
* 扩展ArrayList容量(提供给使用者的方法) :最好在 add 大量元素之前调用,以避免多次扩容
*/
public void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
grow(minCapacity);
}
}
/**
* 可以分配数组的最大值
* OutOfMemoryError: 申请数组大小超过vm限制
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 数组扩容,当size等于数组长度并加入新数据时调用
*/
private Object[] grow() {
return grow(size + 1);
}
/**
*数组扩容
* @param minCapacity 指定最小容量
* @throws OutOfMemoryError 最小容量小于0抛出异常
*/
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));//创建新数组,复制数据
}
/**
* 返回扩容后的数组容量(1.5*oldCapacity)
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//数组原有的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容后的长度,1.5*oldCapacity
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//如果当前数组为空
return Math.max(DEFAULT_CAPACITY, minCapacity);//返回指定容量和默认容量的最大值
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
/**
* 当newCapacity超过MAX_ARRAY_SIZE时,调用此函数
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
常用方法:
/**
*返回arraylist长度
*/
public int size() {
return size;
}
/**
*判断arraylist是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
*判断arraylist是否包含元素
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
*判断元素在arraylist中的索引,不存在返回-1
*/
public int indexOf(Object o) {
return indexOfRange(o, 0, size);
}
/**
*判断元素在arraylist某一范围内的索引,不存在返回-1
*/
int indexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = start; i < end; i++) {
if (es[i] == null) {
return i;
}
}
} else {
for (int i = start; i < end; i++) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
/**
*查找元素在arraylist中的最后出现的索引,不存在返回-1
*/
public int lastIndexOf(Object o) {
return lastIndexOfRange(o, 0, size);
}
/**
*查找元素在arraylist中某一范围内最后出现的索引,不存在返回-1
*/
int lastIndexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = end - 1; i >= start; i--) {//从数组末尾开始遍历
if (es[i] == null) {
return i;
}
}
} else {
for (int i = end - 1; i >= start; i--) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
/**
* 判断size与当前数组大小,如果相等则扩容数组
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
未完。。。
System.arraycopy()与Arrays.copyOf():
Arrays.copyOf():
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
在Arrays.copyOf()中调用了System.arraycopy()方法,参数为源数组和复制长度,方法自动创建目标数组,将源数组全部元素复制到目标数组并返回。
System.arraycopy():
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
native方法,需要指定源数组、目标数组、起始索引和复制长度
上一篇: jdk11源码--CopyOnWriteArrayList源码分析
下一篇: 关于程序开发
推荐阅读