今日心情 :- )
CS61B课程中实现ArrayList 数组扩容
/*
* implement an array list
* 1. addLast()
* 2. getLast()
* 3. size()
* 4. get()
* */
public class AList<T> {
private T[] item;
private int size;
// constructor
public AList(){
size = 0;
item = (T[]) new Object[5];
}
/*
* resize the array capacity
* */
private void resize(int capacity){
T[] a = (T[]) new Object[capacity];
System.arraycopy(item,0,a,0,size);
item = a;
}
public void addLast(T x){
// if the size is larger than the fixed length
// need to expand the array size
if(size == item.length){
T[] a = (T[]) new Object[size*2];
System.arraycopy(item,0,a,0,size);
item = a;
}
item[size] = x;
size += 1;
}
public T getLast(){
return item[size-1];
}
public int size(){
return size;
}
public T get(int x){
return item[x];
}
public T removeLast(){
T x = getLast();
size -= 1;
item[size] = null;
return x;
}
}
实现ArrayList 需要考虑使用的方法有:
(1)insert : 插入
(2)addFirst : 添加到数组首位
(3)addLast:添加到数组尾部
(4)getFirst:获取数组头部元素
(5)getLast:获取数组尾部元素
(6)size:获取当前数组元素总个数
(7)removeLast:删除数组末尾元素
设计时需要在addLast方法中考虑到扩容问题,因为数组的长度定义是固定的,一旦指定数组长度固定就不可改变,如果此时addLast 添加的元素个数 大于 实际数组的固定长度,此时如果不进行数组扩容就会导致溢出。数组的扩容方法:新建一个数组其长度大于原来的数组的长度,然后将原来数组中的元素拷贝到新建的数组中,然后再将新的元素添加到新的数组中。那就需要考虑每次扩容的长度是多少,这就涉及到程序运行的效率和内存空间的 trade off 问题,如果每次扩容的长度较小,操作时间过长且扩容频繁;如果每次扩容的长度过大,可能造成内容空间的利用率低下。所以选择每次扩容的长度需要考虑程序运行的效率和内存空间的 trade off 问题,选择合适的扩容长度。
JAVA中ArrayList的扩容实现
首先ArrayList的实现不是同步的: Note that this implementation is not synchronized
ArrayList 的初始容量是:10
增长函数:(推荐的增长是原来的容量右移一位)
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
Java 对象游离
public T removeLast(){
T x = getLast();
size -= 1;
item[size] = null;
return x;
}
Java的GC回收所有没有引用的对象。在我们对 removeLast() 的实现中,被删除元素的引用仍然存在于数组中,但实际上我们不会再用到这个元素,所以实际上这个元素就是个孤儿,没有谁会再访问它,但Java编译器不知道这一点。这种情况:即一个不需要的对象的引用被保留下来而从不访问,就可以认为这个对象是游离的。要避免这种情况的对象游离,只需将被删除数组元素的值设为null覆盖无用元素的引用,系统在覆盖这个元素为null之后就会识别并回收它的内存。