ArryList源码
2020-09-02 本文已影响0人
我是许仙
ArryList适合查询多 不适合大量新增与删除的操作
属性
/**
* 默认的数组长度
*/
private static final int DEFAULT_CAPACITY = 10;
/**
空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
不会被序列化的一个属性,list的核心是数组,这个属性存储了数组中的值
*/
transient Object[] elementData; // non-private to simplify nested class access
//这里并不是数组的长度,而是数组中存储数组的大小。
private int size;
初始化
/**
* 内部构造一个null的数组
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//新建一个内部的数组对象,长度是 initialCapacity
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
ArryList就是操作数组
add(Object o)
数组的下标是连续的,每次按照elementData[size++]新增数据。如果用默认构造函数new一个Arrylist对象,add的时候会创建一个长度为10的数组。当第11次新增数据的时候,数组的长度超过了10,这个时候触发扩容,每次扩容上一次容量的1.5倍。 int newCapacity = oldCapacity + (oldCapacity >> 1); 由此可见当触发扩容的时候会新新建数组并复制,会有新能开销,所以数组的长度尽量设置合理。
public boolean add(E e) {
//计算容量的大小
ensureCapacityInternal(size + 1); // Increments modCount!!
//添加数组中元素的值
elementData[size++] = e;
return true;
}
//确保内部容量
private void ensureCapacityInternal(int minCapacity) {
//如果内部数组为{}对象 进行容量初始化
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 对比 10 与 minCapacity 中最大的一个数。
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//判断需要的容量 是否比实际的容量大
if (minCapacity - elementData.length > 0)
//进行扩容
grow(minCapacity);
}
//动态扩容核心代码
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);
}
addAll(List list)
在原数组的后面添加新的数组。
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//进行扩容
ensureCapacityInternal(size + numNew); // Increments modCount
//复制原数组的0-0+numNew下标位置数据,复制到目标数组的size位置。
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
add(inde,object)
public void add(int index, E element) {
rangeCheckForAdd(index);
//数组的复制 下标的移动
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
get(index)
通过下标获取list中的内部数组的下标对应的值,因为是下标寻址效率比较高。
public E get(int index) {
//就是数组按照下标获取值
return elementData(index);
}
remove(int index)
public E remove(int index) {
//操作次数自增
modCount++;
//通过下标获取老数据
E oldValue = elementData(index);
//需要移动的元素个数
int numMoved = size - index - 1;
if (numMoved > 0)
//进行数组的copy
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//先运算在赋值,把数组的最后一位设置为null
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
remove(object o)
删除对象先循环内部数组,判断需要删除的值数组内元素是否匹配并找到下标,然后执行删除(数组的复制)
效率低下既要循环找到数据又要进行数组复制。
public boolean remove(Object o) {
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;
}
toArry()
获取集合中的数组。
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
正确实例
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Object[] objects = list.toArray();
for (Object o : objects){
System.out.println(o.toString());
}
错误实例
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
String[] stringS= (String[]) list.toArray();
for (Object o : stringS){
System.out.println(o.toString());
}
image-20200902201510148.png
因为无参数的方法默认返回的是object[]数组。强转会报错
toArry(T[] )
正确的写法,传入一个指定数组
String[] strings = list.toArray(new String[0]);
for (String i : strings) {
System.out.println(i);
}