ArrayList底层实现
原博客地址
ArrayList源代码解析
参考文章(ArrayBox))
package testList;
import java.io.Serializable;
import java.util.RandomAccess;
/**
* 自己动手编写ArrayList代码
* 实现的ArrayList主要的功能如下:默认构造器和一个参数的有参构造器
* add方法;get方法;indexOf方法;contains方法;size方法;isEmpty方法;remove方法
* @author mmz
*/
public class SimpleArrayList<E> implements RandomAccess,Cloneable,Serializable{
private static final int DEFAULT_CAPICITY=10;//常量一般都是static final修饰
int size=0;//用来记录数组内存储的有效元素个数,而不是数组空间
private Object[] elementData;//声明一个数组变量elementData
//java源码:private transient Object[] elementData; transient让某些被修饰的成员属性变量不被序列化
//ArrayList无参构造器
public SimpleArrayList() {
this(DEFAULT_CAPICITY);//构造函数重载,this()调用的其实就是构造函数,此处调用的是有参构造函数
}
//ArrayList有参构造器
public SimpleArrayList(int size) {
if(size<0) {
throw new IllegalArgumentException("默认大小"+size);
}else {
elementData=new Object[size];//创建大小为size的数组 并将它复制给之前声明为Object[]的变量elementData
}
}
//实现add方法(1)
public void add(E e) {
isCapicityEnough(size+1);//做一个判断,是否需要扩容。size+1是添加一个元素后数据的总长度
elementData[size++]=e;
}
//实现add方法
public void add(int index,E e) {//1.java中大部分,可以说全都是从0开始的,比如数组,集合等2.在数据库中则有不少都是从1开始的,首先记录集里是从1开始的,截取字符串时也是从1开始,而java中则是从0开始,
checkRangeForAdd(index);
isCapicityEnough(size+1);
System.arraycopy(elementData,index,elementData,index + 1,size - index);
elementData[index] = e;
size++;
/**
* System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制。
* 其函数原型是:public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
* src:源数组;
srcPos:源数组要复制的起始位置;
dest:目的数组;
destPos:目的数组复制的起始位置;
length:复制的长度。
注意:src and dest都必须是同类型或者可以进行转换类型的数组
int[] ids = { 1, 2, 3, 4, 5 };
System.out.println(Arrays.toString(ids)); // [1, 2, 3, 4, 5]
// 把从索引0开始的2个数字复制到索引为3的位置上
System.arraycopy(ids, 0, ids, 3, 2);//[1, 2, 3, 1, 2]
*/
}
//判断是否需要扩容,不需要的话算了,需要就用explicitCapacity扩
public void isCapicityEnough(int size) {
if(size>DEFAULT_CAPICITY) {//如果数据的长度大于默认空间,则扩容
explicitCapacity(size);
}
if(size<0) {
throw new OutOfMemoryError();
}
}
//扩容函数
private final static int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;//??
public void explicitCapacity(int capacity) {
int newLength=elementData.length*2;//按照两倍扩容
if(newLength-capacity<0) {//如果扩容后长度仍然小于加入新元素后数组的长度,则将加入新元素后数组的长度赋值给新长度
newLength=capacity;
}
if(newLength>MAX_ARRAY_LENGTH) {//判断若扩容后长度大于给定的最大值,则新长度重新赋值
newLength=((capacity>MAX_ARRAY_LENGTH)?Integer.MAX_VALUE:MAX_ARRAY_LENGTH);
}
}
//判断是否越界
public void checkRangeForAdd(int index) {//java中的索引一般是从0开始;数据库中index一般从1开始
if(index<0||index>size) {
throw new IndexOutOfBoundsException("指定的index超过界限");
}
}
//实现get方法,get方法用来得到容器中指定下标的元素。方法实现比较简单,直接返回数组中指定下标的元素即可。
public E getElement(int index) {
checkRangeForAdd(index);
return (E) elementData[index];
}
//实现indexOf方法用来得到指定元素的下标。实现起来比较简单,需要判断传入的元素,
public int indexOf( Object o) {
if(o!=null) {//判断传入的元素是否为null
for(int i=0;i<size;i++) {
if(elementData[i].equals(o)) {
return i;
}
}
}else {
for(int i=0;i<size;i++) {
if(elementData[i]==null) {
return i;
}
}
}
return -1;//匹配成功就返回下标,匹配失败就返回-1。因为返回值类型是int
}
//contains方法,用来判断该容器中是否包含指定的元素。
public boolean contains(Object o) {
return indexOf(o)>=0;//根据指定元素,寻找索引值,根据indexOf方法,若找不到该元素就返回-1,所以若indexOf返回大于0则
}
//size方法用来得到容器类的元素个数
public int size() {
return size;//elementData.length
}
//isEmpty方法用来判断容器是否为空
public boolean isEmpty() {
return size()==0;
}
//remove方法(1)是用来对容器类的元素进行删除
// public void remove(Object o) {
// int aindex=indexOf(o);
// System.arraycopy(elementData, aindex+1, elementData, aindex, size-aindex);
// elementData[size-1]=null;
// }自己写的,不知道ok否
public E remove(int index) {
E value = getElement(index);
int moveSize = size - index - 1;
if (moveSize > 0){
System.arraycopy(elementData,index + 1, elementData,index,size - index - 1);
}
elementData[--size] = null;
return value;//返回被删除的元素
}
public boolean remove(Object o) {
if(contains(o)) {
remove(indexOf(o));
return true;
}else {
return false;
}
}
}