Collection-List-ArrayList
1.List接口概念
List接口继承了Collection接口以定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。面向位置的操作包括插入某个元素或Collection的功能,还包括获取,除去或更改元素的功能。在List中搜索元素可以从列表的头部或者尾部开始,如果找到元素,还将报告元素所在的位置。
相关方法
方法 | 说明 |
---|---|
void add(int index,Object element) | 在指定位置index上添加元素element |
boolean addAll(int index,Collection c) | 将集合c的元素添加到指定位置index |
Object get(int index) | 返回List中指定位置的元素 |
int indexOf(Object o) | 返回第一个出现元素o的位置,否则返回-1 |
int lastIndexOf(Object o) | 返回最后一个出现元素o的位置,否则返回-1 |
Object remove(int index) | 删除指定位置上的元素 |
Object set(int index,Object element) | 用元素element取代位置index上的元素,并且返回旧的元素 |
2.ArrayList
ArrayList实现了List接口的所有方法,可以看作是“长度可调节的数组”,可以包含任何类型的数据(包括null,可重复)。ArrayList大体上和Vector一致,唯一的区别就是ArrayList非线程安全,Vector线程安全。但是Vector线程安全的代价较大。
2.1类结构
ArrayList类主要包含如下两个成员变量。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
transient Object[] elementData;//elementDate为Object类型数组,用于存放ArrayList数据
private int size;//size表示数组元素个数(并非数组容量)
}
ArrayList还包含了一些常量
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//数组默认初始化容量为10
private static final int DEFAULT_CAPACITY=10;
//表示空数组
private static final Object[] EMPTY_ELEMENTDATE={};
//也是空数组,但是和EMPTY_ELEMENTDATE分开
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATE={};
}
2.2方法解析
2.2.1构造函数
2.2.1.1 public ArrayList(int initialCapacity)
public ArrayList(int initialCapacity){
if(initialCapacity>0){
this.elementDate = new Object[initialCapacity]
}else if(initialCapacity==0){
this.elementDate = EMPTY_ELEMENTDATE;
}else{//否则就抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
2.2.1.2 public ArrayList()
public ArrayList(){
this.elementDate = DEFAULTCAPACITY_EMPTY_ELEMENTDATE;
}
2.2.1.3 public ArrayList(Collection<? extends E> c)
创建一个包含指定集合c数据的ArrayList。复制数组是因为在某些情况下调用集合的toArray()方法返回的类型不是Object[].class
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();//复制数组
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
2.2.2 一些常用的构造方法
2.2.2.1 add(E e)
add(E e)用于尾部添加元素
public boolean add(E e){
//用于确定数组容量
ensureCapacityInternal(size+1);
elementDate[size++]=e;//将元素添加到数组尾部
return true;
}
内部过程如下
- 任何一个空的ArrayList在添加第一个元素时,内部数组容量将被扩容为10;
- 扩容时,newCapacity为oldCapacity的1.5倍;
- 数组容量最大为Integer.MAX_VALUE;
- 尾部添加元素不用移动任何元素,所以速度快
public boolean add(E e) {
// 用于确定数组容量,e=hello,size=0
ensureCapacityInternal(size + 1);
// 末尾添加元素,然后size递增1
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) { // minCapacity=1,elementData={}
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// DEFAULT_CAPACITY=10,minCapacity=1,故返回10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//判断是否要扩容的方法
private void ensureExplicitCapacity(int minCapacity) { // minCapacity=10
modCount++;
// minCapacity=10,elementData.length=0,所以调用grow方法扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//扩容为1.5倍
private void grow(int minCapacity) { //minCapacity=10
// oldCapacity=0
int oldCapacity = elementData.length;
// newCapacity为oldCapacity的1.5倍,这里为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
// newCapacity=0,minCapacity=10,所以该条件成立
if (newCapacity - minCapacity < 0)
// newCapacity=10
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 复制到新数组,数组容量为10
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// MAX_ARRAY_SIZE常量值为Integer.MAX_VALUE - 8,通过
// 这段逻辑我们可以知道,ArrayList最大容量为Integer.MAX_VALUE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
2.2.2.2 add(int index, E element)
add(int index, E element)
用于在指定位置添加元素:
public void add(int index, E element) {
// 下标检查
rangeCheckForAdd(index);
// 确定数组容量,和上面add(E e)方法介绍的一致
ensureCapacityInternal(size + 1);
// 将原来index后面的所有元素往后面移动一个位置
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// index处放入新元素
elementData[index] = element;
// size递增
size++;
}
private void rangeCheckForAdd(int index) {
// 下标比size大或者下标小于0,都会抛出下标越界异常
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
这里涉及到元素移动,所以速度较慢。