ArrayList详解
- 初识ArrayList
- 成员变量
- 方法列表
-
- 按照定义顺序介绍
-
- public ArrayList(int initialCapacity)
- public ArrayList()
- public ArrayList(Collection<? extends E> c)
- public void trimToSize()
- public void ensureCapacity(int minCapacity) //手动对集合进行扩容
- · private static int calculateCapacity(Object[] elementData, int minCapacity)
- · private void ensureCapacityInternal(int minCapacity)
- · private void ensureExplicitCapacity(int minCapacity)
- · private void grow(int minCapacity)
- · private static int hugeCapacity(int minCapacity)
- public int size()
- public boolean isEmpty()
- public boolean contains(Object o)
- public int indexOf(Object o)
- public int lastIndexOf(Object o)
- public Object clone()
- public Object[] toArray()
- public T[] toArray(T[] a)
- E elementData(int index)
- public E get(int index)
- public E set(int index, E element)
- public boolean add(E e)
- public void add(int index, E element)
- public E remove(int index)
- public boolean remove(Object o)
- private void fastRemove(int index)
- public void clear()
- public boolean addAll(Collection<? extends E> c)
- public boolean addAll(int index, Collection<? extends E> c)
- protected void removeRange(int fromIndex, int toIndex)
- private void rangeCheck(int index)
- private void rangeCheckForAdd(int index)
- private String outOfBoundsMsg(int index)
- public boolean removeAll(Collection<?> c)
- public boolean retainAll(Collection<?> c)
- private boolean batchRemove(Collection<?> c, boolean complement)
- private void writeObject(ObjectOutputStream s) throws IOException
- private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException
- 精解列表
-
- 3-ArrayList实现序列化接口就是为了在网络上传输,那为什么存放数据的elementData,要用transient修饰呢?writeObject()/readObject()又是做什么的呢?
- 4-当通过构造方法ArrayList(Collection<? extends E> c)创建得到ArrayList对象后,为什么对集合c元素属性的的所有修改都体现在生成的ArrayList上?
- 5-通过toArray()将集合转为Object[] 可能会有哪些问题?为什么《阿里巴巴编程规范》中强制要求使用toArray(T array)方法来将集合转为数组?
- 6-用户自己调用容器的扩容方法,为什么不能全凭用户想法扩容到指定大小呢?而是要与默认1.5倍扩容大小进行比较,如果1.5倍扩容后的大小比用户定义的大,那么就按照1.5倍进行扩容,而不按照用户想要的大小进行扩容?
初识ArrayList
- ArrayList的继承和实现的结构为
ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- 抽象类AbstractList中定义了modCount属性,这个参数是指当前列表的结构被修改的次数
- 结构上的修改指的是那些改变了list的长度大小或者使得遍历过程中产生不正确的结果的其它方式
- 请留心每一个操作ArrayList中改变存储内容或者改变结构的方法,都会对modCount属性进行++操作
protected transient int modCount = 0;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
- ArrayList在创建对象的时候并不会初始化容量,当在add或者其他方法调用的时候才会初始化容量【参见精解1】
- System.arraycopy复制数组为浅克隆【参见精解2】
- System.arraycopy是一个native函数,复制数组时并不是传统意义的——通过数组下标从最后一位依次向后移动一位,而是直接对内存中的数据块进行复制的,是一整块一起复制的,这样效率会大大提升【参见精解2】
成员变量
//序列化ID
private static final long serialVersionUID = 8683452581122892189L;
//ArrayList的默认初始容量大小
private static final int DEFAULT_CAPACITY = 10;
//空对象数组,用于空实例的共享空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {
};
//空对象数组,使用无参构造器实例化对象时,将此值赋给elementData
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
//存放当前数据,ArrayList底层使用的是数组来保存元素
//ArrayList实现Serializable接口就是允许序列化的,那么为什么该变量却用transient修饰呢?【参见精解3】
transient Object[] elementData;
//记录list中存放数据的大小,而不是指数组的length
//比如 elementData = {"gao","shao",null,null,null}
//elementData.length 的结果是5;而size保存的数值是2
private int size;
//集合所允许的最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
方法列表
按照定义顺序介绍
public ArrayList(int initialCapacity)
—— 自定义初始化容器大小
//自定义初始化容器大小
//当传入的值<0时,抛出异常
//当传入的值=0时,使用默认大小的数组初始化
//当传入的值>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()
—— 无参构造
//无参构造方法,使用默认大小的数组初始化
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c)
—— 通过传入集合来初始化当前集合
//通过传入集合来初始化当前集合
//将传入的集合中的元素引用复制到当前生成的ArrayList集合中,并且对原先集合中元素的任何修改都会体现到当前集合上【参见精解4】
public ArrayList(Collection<? extends E> c) {
//将传入的集合转为Object数组赋值给elementData
elementData = c.toArray();
if ((size = elementData.length) != 0) {
//已经通过上面的c.toArray()将放回的Object[]赋值到elementData上了,为什么还要进行判断呢?
//因为c.toArray()返回的内容类型有可能不是Object[]数组,这是一个小bug,如果不进行判断处理的话,客户使用时会有隐患【参见精解5】
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//将空数组赋值给elementData
this.elementData = EMPTY_ELEMENTDATA;
}