以数组实现。节约空间,但数组有容量限制。超出限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值。默认第一次插入元素时创建大小为10的数组。
按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。
ArrayList重要的一点是它的自动扩容,即我们常说的“动态数组”。
下面将代码示例ArrayList的实现,为与类库中的类区别出来,这里把该类命名为MyArrayList。不提供MyCollection或MyList接口,MyArrayList是独立的。ArrayList类的实现类的要点如下:
1. MyArrayList将保持基础数组,数组容量,以及存储在MyArrayList中的当前项数。
2. MyArrayList将提供一种机制以改变基础数组的容量。通过获得一个新数组,将老数组拷贝到新数组中来改变数组的容量,允许虚拟机回收老数组。
3. MyArrayList将提供get和set的实现。
4. MyArrayList将提供基本的操作例程,如size、isEmpty和clear,它们是典型的单行程序;还提供remove,以及两种不同版本的add。如果数组的大小和容量相同,那么这两个add例程将增加容量。
5. MyArrayList将提供一个实现Iterator接口的类。这个类将存储迭代系列中的下一项的下标,并提供next、hasNext和remove等方法的实现。MyArrayList的迭代器方法直接返回实现Iterator接口的该类的新构造器的实例。
下面写基本类MyArrayList,想它的Collection API的对应类一样,存在某种错误检测以保证合理的限界,但为了把专注于编写迭代器的基本方面内容,这里不检测可能使迭代器无效的结构上的修改,也不检测非法的迭代器remove方法。代码清单如下:
package com.afy.datastructures.collection;
import java.util.Iterator;
import javax.sql.rowset.JdbcRowSet;
import com.sun.glass.ui.Size;
public class MyArrayList<AnyType> implements Iterable<AnyType> {
private static final int DEFAULT_CAPACITY = 10;
private int theSize;
private AnyType [] theItems;
public MyArrayList(){
doClear();
}
private void doClear() {
theSize = 0;
ensureCapacity(DEFAULT_CAPACITY );
}
private int size() {
return theSize;
}
public boolean isEmpty(){
return size() ==0;
}
public void trimToSize(){
ensureCapacity(size());
}
public AnyType get(int idx){
if (idx<0 || idx>=size())
throw new ArrayIndexOutOfBoundsException();
return theItems[idx];
}
public AnyType set(int idx , AnyType newVal){
if (idx < 0 || idx >=size())
throw new ArrayIndexOutOfBoundsException();
AnyType old = theItems[idx];
theItems[idx] = newVal;
return old;
}
private void ensureCapacity(int newCapacity) {
if (newCapacity<theSize)
return;
AnyType [] old = theItems;
theItems = (AnyType[]) new Object[newCapacity];
for(int i = 0;i<size();i++)
theItems[i] = old[i];
}
public boolean add(AnyType x){
add(size(),x);
return true;
}
public void add(int idx, AnyType x) {
if (theItems.length==size()) {
ensureCapacity(size()*2+1);
for(int i=theSize;i>idx;i--)
theItems[i] = theItems[i-1];
theItems[idx]=x;
theSize++;
}
}
public AnyType remove(int idx) {
AnyType removeItem = theItems[idx];
for(int i = idx; i<size()-1;i++)
theItems[i] = theItems[i+1];
theSize--;
return removeItem;
}
@Override
public Iterator<AnyType> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator implements java.util.Iterator<AnyType>{
private int current = 0;
public boolean hasNext(){
return current < size();
}
public AnyType next(){
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
return theItems[current++];
}
public void remove(){
MyArrayList.this.remove(--current);
}
}
}
如代码所示,MyArrayList把大小及数组作为其数据成员进行存储。然后接着是几个短例程clear、size、trimToSize、isEmpty、get以及set的实现。
接着是ensureCapacity例程,容量的扩充是用于早先描述的相同的方法来完成的:存储对原始数组的一个引用,为新数组分配内存,并将旧内容拷贝到新数组中。例程ensureCapacity也可以用于收缩基础数组,不过要指定的新容量至少和原大小一样才适用。否则,ensureCapacity的要求将被忽略。由于泛型数组的创建是非法的,所以要创建一个泛型类型限界的数组,然后使用一个数组进行类型转换。这会产生一个编译器警告,但在泛型集合的实现中是不可避免的。
remove方法类似与add,只是那些位于指定位置上或指定位置后的元素向低移动到一个位置。
剩下的例程处理iterator方法和相关迭代器类的实现。iterator方法直接返回ArrayListIterator类的一个实例, 该类是一个实现Iterator接口的类。ArrayListIterator存储当前位置的概念,提供hasNext、next和remove的实现。当前位置表示要被查看的下一元素(的数组下标),因此初始时当前位置为0。