在学习了集合框架后,为了更透彻的理解集合的底层源码,有必要自己实现一个ArrayList
以下是我的源码:
class MyArrayList<T> implements Iterable<T>{
private T[] elemdata;
private static final int DEFAULT_CAPACITY = 10;
private int size;
public MyArrayList(int capacity) {
if(capacity < 0) {
try {
throw new IllegalAccessException("传入容量大小异常!");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
elemdata = (T[])new Object[capacity];
size = 0;
}
public MyArrayList() {
this(DEFAULT_CAPACITY);
}
//判断是否为满
public boolean isFull() {
return size >= elemdata.length;
}
//扩容函数
public void grow() {
/**
* 关于为什么扩容是2倍加2,我们假设是二倍扩容,我的大小定义为0,那么在我指定位置添加的时候,扩容
* 始终是2*0还是0,如果是2倍加1的话,我们在这里进行拷贝的时候会用到下一个位置,也就是说我们的length是1,但是
* 我们的拷贝中有i+1这样的元素,所以多扩容一个这样防止数组越界
*/
elemdata = Arrays.copyOf(elemdata,elemdata.length*2+2);
}
//索引异常函数
public void rangeCheck(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException("传入索引异常");
}
}
//添加元素到末尾的函数
public boolean add(T data) {
//判断是否需要扩容
if(isFull()) {
grow();
}
elemdata[size++] = data;
return true;
}
//按照指定位置插入元素
public boolean add(int index,T data) {
if(index < 0 || index > size) {
throw new IndexOutOfBoundsException("下标越界");
}
size++;
if(isFull()) {
grow();
}
for (int i = size-1; i >= index ; i--) {
elemdata[i+1] = elemdata[i];
}
elemdata[index] = data;
return true;
}
//根据索引删除
public T remove(int index) {
rangeCheck(index);
T temp = elemdata[index];
System.arraycopy(elemdata,index+1,elemdata,index,size-index-1);// 0 1 2 3 4
elemdata[--size] = null;
return temp;
}
//根据值删除
public boolean remove(T t) {
if(t == null) {
for (int i = 0; i < size; i++) {
if(elemdata[i] == t) {
System.arraycopy(elemdata,i+1,elemdata,i,size-i-1);
elemdata[--size] = null;
return true;
}
}
} else {
for (int i = 0; i < size; i++) {
if(elemdata[i].equals(t)) {
System.arraycopy(elemdata,i+1,elemdata,i,size-i-1);
elemdata[--size] = null;
return true;
}
}
}
return false;
}
//获得指定位置的元素
public T get(int index) {
rangeCheck(index);
return elemdata[index];
}
//修改指定位置的值
public T set(int index,T data) {
rangeCheck(index);
T old = elemdata[index];
elemdata[index] = data;
return old;
}
//重写toString方法
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i <size; i++) {
builder.append(elemdata[i] + " ");
}
return builder.toString();
}
@Override
public Iterator<T> iterator() {
return new Itr();
}
class Itr implements Iterator<T>{
private int index = -1;
@Override
public boolean hasNext() {
return (index+1) < size;//1
}
@Override
public T next() {
return elemdata[++index];
}
@Override
public void remove() {
MyArrayList.this.remove(index--);
}
}
}
注意:
1.我实现的ArrayList只是一些基本的功能,有些还没有实现,比如ListIterator等,以后的学习中会逐渐补充
2.我们在写自己的集合类时一定要注意一些方法在接受形参index时,要注意index范围的判断,看看这个索引位置是否是数组的合法位置,如果不是抛出相应的异常。
3.数组进行扩容的时候的注意事项,因为我是在添加元素的时候进行扩容判断,如果我初始为0,这时候就要进行相应的调整,我的扩容是2倍+2,具体原因可以看看我的扩容代码处的注释。
4.我实现的迭代器功能只是满足了基本的迭代器功能,并没有像jdk源码那样,有fail-fast快速失败,以确保在迭代过程中不会出现集合结构上的变化。