文章目录
前言
开发一个springboot项目,其本质便是对数据库的各种操作,所以在系统开发过程中,学会如何对数据库的增删改查(CRUD)十分重要,那么其中哪个操作用的是最多的呢?毫无疑问,查询操作是最多的(如:分页查询,修改时原数据在页面的回显等),那么查询时用的最多的便是ArrayList集合,接下来将仿照ArrayList源码写一个MyArrayList类,带大家简单了解一下ArrayList的源码。
一、MyArrayList类的组成
一个类的包含有属性,构造方法(无参构造方法和有参构造方法),方法等,那么MyArrayList类首先要继承ArrayList类,然后重写父类的构造方法和ArrayList提供的各种方法(注:不需要重写父类所有方法)
二、构造方法重写
1.ArrayList定义
首先先来看下顶级接口Collection的方法:
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
}
然后是接口List的定义:
public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll( int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
E get( int index);
E set( int index, E element);
void add( int index, E element);
E remove( int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator( int index);
List<E> subList( int fromIndex, int toIndex);
}
再看下ArrayList的定义:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以看出ArrayList继承AbstractList(这是一个抽象类,对一些基础的list操作进行封装),实现List,RandomAccess,Cloneable,Serializable几个接口。RandomAccess接口的主要作用是标识一个类是否支持随机访问。Cloneable接口的主要作用是作为一个标记,表明实现了该接口的类支持对象的克隆操作。Serializable接口的主要作用是标识一个类是否可以序列化。
2.MyArrayList定义
模仿ArrayList的定义,写MyArrayList定义:
public class MyArrayList<E> extends AbstractList<E> implements
List<E>, RandomAccess, Cloneable, java.io.Serializable
3.MyArrayList无参构造和有参构造
//属性:
//数组
private Object[] elementData;
//数组大小
private int size;
//有参构造:
//构造一个具有指定容量的list
public MyArrayList(int index){
super();
//如果输入的容量小于0,则会抛出异常
if (index < 0){
throw new IllegalArgumentException( "索引输入不合法: " + index);
}
//底层用的是数组保存数据
this.elementData = new Object[index];
}
//无参构造:
public MyArrayList(){
//构造一个容量为10的list
this(10);
}
3.MyArrayList的方法
下面写几个常用的方法:
1.add(int index, E e)方法:在指定位置插入一个元素
public void add(int index, E e) {
//如果输入的位置索引大于数组长度或者小于0,则抛出异常
if (index > size || index < 0)
throw new IndexOutOfBoundsException("输入不合法");
//用ensureCapacity(int minCapacity)方法进行数组容量检查
ensureCapacity( size+1);
/*
用System.arraycopy进行数组拷贝
System.arraycopy第一个参数:从A数组拷贝
第二个参数:从哪个索引开始拷贝
第三个参数:拷贝到B数组
第四个参数:拷贝的数据从B哪个索引开始存放
第五个参数:拷贝几个数据
*/
System.arraycopy(e, index, e, index + 1, size - index);
elementData[index] = e;
//数组容量++
size++;
}
//数组容量检查,不够时则进行扩容
public void ensureCapacity( int minCapacity) {
modCount++;
// 当前数组的长度
int oldCapacity = elementData .length;
// 最小需要的容量大于当前数组的长度则进行扩容
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
// 新扩容的数组长度为旧容量的1.5倍+1
int newCapacity = (oldCapacity * 3)/2 + 1;
// 如果新扩容的数组长度还是比最小需要的容量小,则以最小需要的容量为长度进行扩容
if (newCapacity < minCapacity)
newCapacity = minCapacity;
//用Arrays.copyOf进行数据拷贝
elementData = Arrays.copyOf( elementData, newCapacity);
}
}
2.add(E e)方法:就是将数据添加到数组的末尾
3.remove(int index)方法:删除指定索引的元素
//根据索引位置删除元素
public E remove(int index){
// 数组越界检查
RangeCheck(index);
modCount++;
//去除要删除的元素,供返回使用
E oldValue = (E) elementData[index];
//计算出要拷贝的数量
int num = size - index - 1;
//拷贝数组
System.arraycopy(elementData, index+1, elementData, index, num);
//将数组最后一个元素置空,好让gc回收
//数组长度-1
elementData[--size] = null;
//返回删除的元素
return oldValue;
}
//数组越界检查
public void RangeCheck(int index) {
if (index >= size )
throw new IndexOutOfBoundsException("索引越界");
}
}
4.set(int index, E element):修改指定索引元素
//修改指定索引元素
public E set(int index, E e) {
//数组越界检查
RangeCheck(index);
//获取修改的元素,供返回使用
E oldValue = (E) elementData[index];
//修改元素为新元素
elementData[index] = e;
//返回修改的元素
return oldValue;
}
5.get(int index):获取指定索引的元素
//查询指定索引元素
public E get(int index) {
//数组越界检查
RangeCheck(index);
return (E) elementData[index];
}
6.isEmpty():判断list是否为空
public boolean isEmpty() {
return size == 0;
}
7.indexOf(Object o):返回此list中首次出现的指定元素的索引,或如果此list不包含元素,则返回 -1
public int indexOf(Object o) {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
return -1;
}
8.lastIndexOf(Object o) :返回此list中最后一次出现的指定元素的索引,或如果此list不包含索引,则返回 -1。
public int lastIndexOf(Object o) {
for (int i = size - 1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
return -1;
}
总结
方法有很多,这里只写了部分常用的方法,其他方法可以看ArrayList源码比葫芦画瓢。