目录
1、简单说一下ArrayList用来干嘛的?
ArrayList是数组列表,主要用来装载数据, 当我们装载的是基本类型的数据int,long,boolean,short,byte…的时候我们只能存储他们对应的包装类,它的主要底层实现是数组 Object[] elementData
。
ArrayList 查询效率高,增删效率低,线程不安全。使用频率很高。
2、LinkedList、 Vector 与ArrayList
我们使用多的是查询,ArrayList查询效率高。
如果涉及频繁的增删可以使用LinkedList。
如果需要线程安全就使用Vector。
3、ArrayList扩容机制
数组的长度是有限制的,而ArrayList是可以存放任意数量对象,长度不受限制,那么他是怎么实现的呢?
其实实现方式比较简单,他就是通过数组扩容的方式去实现的。
看源码!
初始容量为10
//默认初始容量为10
private static final int DEFAULT_CAPACITY = 10;
ArrayList是怎么进行扩容的
还是找源码。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
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);
}
可以看到扩容后的新容量=之前的容量+之前的容量右移1位(也就是除于2)
举个例子来看一下:
现在我们使用默认的初始容量为10,填满元素。
首先他会重新定义一个长度为10+10/2的数组也就是新增一个长度为15的数组。
然后把原数组的数据,原封不动的复制到新数组中,这个时候再把指向原数的地址换到新数组,ArrayList就这样完成了一次改头换面。
如果你传入了初始容量就用你传入的参数,如果没有,就使用默认的大小。
4、ArrayList怎么进行新增操作的
有两种方式进行新增操作。
第一种直接添加元素。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
在新增之前有一步检验长度的判断ensureCapacityInternal
,就是说如果长度不够,是需要扩容的,关于怎么扩容上面已将讲过。
第二种指定index新增。
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++;
}
在进行校验之后,及逆行了数组的copy,找一下arraycopy。
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
是一个native方法。
举个例子来理解一下这个方法:
比如有下面这样一个数组我需要在index 5的位置去新增一个元素A 。
那从代码里面我们可以看到,他复制了一个数组,是从index 5的位置开始的,然后把它放在了index 5+1的位置 。
给我们要新增的元素腾出了位置,然后在index的位置放入元素A就完成了新增的操作了 。
5、 ArrayList(int initialCapacity)会不会初始化数组大小?
不会初始化数组大小。
通过代码看一下:
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList(10);
System.out.println(arrayList.size());
arrayList.set(5,1);
}
}
输出结果:报错了。
6、ArrayList怎么进行删除操作的?
看源码:
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
从源码中我们可以看到还是arraycopy。
还是举个例子来理解:
我们现在要删除index 为5的这个位置。
那代码他就复制一个index5+1开始到最后的数组,然后把它放到index开始的位置
index5的位置就成功被”删除“了其实就是被覆盖了,给了你被删除的感觉。
同理他的效率也低,因为数组如果很大的话,一样需要复制和移动的位置就大了。