ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。继承于 AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。
ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandomAccess 接口, RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持快速随机访问的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
ArrayList 实现了Cloneable 接口,即覆盖了函数 clone(),能被克隆。
ArrayList 实现java.io.Serializable 接口,这意味着ArrayList支持序列化,能通过序列化去传输。
和 Vector 不同,ArrayList 中的操作不是线程安全的!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者 CopyOnWriteArrayList。
ArrayList是线性表,线性表的顺序存储,插入删除元素的时间复杂度为O(n),求表长以及增加元素,取第 i 元素的时间复杂度为O(1)。
话不多说,现在开始手写核心方法。
public class MyArrayList {
private static final int DEDFAULT_CAPACITY=10;
private Object elementData[];
public int size=0;
public MyArrayList() {
elementData=new Object[DEDFAULT_CAPACITY];
}
public MyArrayList(int capacity) {
elementData=new Object[capacity];
}
/**
* 定义add方法
* 功能:主要用于向数组中添加元素
* @param obj
*/
public void add(Object obj) {
elementData[size++]=obj;
}
/**
* 重写toString()方法
* 功能:主要用于输出MyArrayList
*/
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append("[");
for(int i=0;i<size;i++) {
sb.append(elementData[i]+",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
MyArrayList myList=new MyArrayList();
myList.add(222222222);
myList.add("hello");
myList.add("world");
myList.add("1+2="+(1+2));
System.out.println(myList);
}
}
简单吧!那我就不解释了!
add方法改进
/**
* 定义add方法
* 功能:主要用于向数组中添加元素
* @param obj
*/
public void add(E obj) {
//数组已满
if(size==elementData.length) {
//创建一个新的数组 容量为当前数组的1.5倍
Object[] newArray=new Object[elementData.length+(elementData.length>>1)];//新容量=10+10/2
//数组拷贝
System.arraycopy(elementData, 0, newArray, 0, elementData.length);
//将数组引用指向新数组
elementData=newArray;
}
elementData[size++]=obj;
}
构造函数越界检查,新增set和get方法,数组越界检查
public MyArrayList04(int capacity) {
//容量合法性检查
if(capacity<0) {
throw new RuntimeException("容量不合法:"+capacity);
}else if(capacity==0) {
elementData=new Object[0];
}else {
elementData=new Object[capacity];
}
}
/**
* 为链表的某个元素赋值
* @param obj
* @param index
*/
public void set(int index,E obj) {
checkRange(index);
elementData[index]=obj;
}
/**
* 返回指定位置的元素
* @param index
* @return 返回指定元素
*/
@SuppressWarnings("unchecked")
public E get(int index) {
checkRange(index);
return (E)elementData[index];
}
/**
* 索引合法性判断 范围[0,size-1]
* @param index
*/
public void checkRange(int index) {
if(index<0||index>size-1) {
throw new RuntimeException("索引不合法:"+index);
}
}
完善功能,新增isEmpty(),remove(),size()方法
/**
* 返回数组的当前实际大小
* @return 数组的实际大小
*/
public int size() {
return size;
}
/**
* 判断数组是否为空
* @return 数组的状态
*/
public boolean isEmpty() {
return size==0;
}
/**
* 根据元素移除数组中的该元素
* @param element
*/
public void remove(E element) {
//链表中遍历该元素
for(int i=0;i<size;i++) {
if(element.equals(elementData[i])) {//通过equals()方法判断是否存在该元素
remove(i);
}
}
}
/**
* 根据索引移除数组中的元素
* @param i
*/
public void remove(int index) {
//边界检查
checkRange(index);
//数组拷贝
int numMoved=size-1-index;
if(numMoved>0) {
System.arraycopy(elementData, index+1, elementData, index, numMoved);
}
elementData[--size]=null;
}
大功告成!!!
附完整版源代码