文章目录
一、ArrayList的构造
二、ArrayList常见操作
三、模拟实现
1.创建类及其构造方法
public class MyArrayList1<E> {
private Object[] array;
private int size;
//构造方法:无参构造
public MyArrayList1(){
}
public int size(){
return size;
}
}
由于列表中存放元素各种类型都有可能,这里采用泛型<E>。
2.指定顺序表初始容量
public MyArrayList1(int initCapacity){
if(initCapacity>=0){
array=new Object[initCapacity];
}else{
throw new IllegalArgumentException("初始容量为负数");
}
}
初始容量必须为正整数,否则抛异常。
3.判断列表是否为空
public boolean isEmpty(){
return size==0;
}
4.尾插
public boolean add(E e){
ensureCapacity(size+1);
array[size++]=e;
return true;
}
//扩容
private static final int MAX_ARRAY_SIZE=Integer.MAX_VALUE-8;
private void ensureCapacity(int initCapacity){
int oldCapacity= array.length;
//初步预计按照1.5倍大小扩容
int newCapacity=oldCapacity+(oldCapacity>>1);
//如果扩容后小于初始容量,则仍然按照初始容量
if(newCapacity<initCapacity){
newCapacity=initCapacity;
}
//如果扩容后超过最大容量,则按照最大容量
if(newCapacity>MAX_ARRAY_SIZE){
newCapacity=MAX_ARRAY_SIZE;
}
array= Arrays.copyOf(array,newCapacity);
}
步骤:
1.扩容
2.将元素放在size的位置
3.将size+1
细化扩容:
1.首先设置列表的最大值:
数组对象的形状和结构(如int值数组)与标准Java对象类似。主要区别在于数组对象有一个额外的元数据,用于表示数组的大小。所以这里的最大值是整型最大值-8.
2.初步预计按照1.5倍大小扩容,如果扩容后小于初始容量,则仍然按照初始容量;如果扩容后超过最大容量,则按照最大容量。
3.使用copyOf进行扩容
5.将e插入到index位置
public void add(int index,E e){
rangeCheckForAdd(index);
ensureCapacity(size+1);
//将index及其之后的元素统一往后搬移一个位置
for(int i=size-1;i>=index;i--){
array[i+1]=array[i];
}
array[index]=e;
size++;
}
//检测插入时下标是否异常
private void rangeCheckForAdd(int index){
if(index>size){
throw new IllegalArgumentException("add下标越界");
}
}
步骤:
1.检测插入时下标是否异常,是的话抛出异常
2.扩容
3.将index及其之后的元素统一往后搬移一个位置(这里一定要注意从后往前搬,如果从前往后搬会出现搬移的所有元素都是同一个元素的现象)
6.删除index位置上元素
public E remove(int index){
rangeCheck(index);
E e=(E)array[index];
//将index之后的元素统一往前搬移一个位置
for(int i=index+1;i<size;i++){
array[i-1]=array[i];
}
size--;
return e;
}
//检测下标是否异常
private void rangeCheck(int index){
if(index<0||index>=size){
throw new IndexOutOfBoundsException("下标越界");
}
}
步骤:
1.检测下标是否异常,是的话抛出异常
2.将下标为index的元素强转为E类型,方便后续返回
3.将index之后的元素统一往前搬移一个位置(从前往后)
7.删除遇到的第一个o
public boolean remove(Object o){
int index=indexOf(o);
if(index==-1){
return false;
}
remove(index);
return true;
}
//获取o第一次出现的位置
private int indexOf(Object o){
if(o==null){
for(int i=0;i<size;i++){
if(array[i]==null){
return i;
}
}
}else{
for(int i=0;i<size;i++){
if(array[i]==o){
return i;
}
}
}
return -1;
}
步骤:
1.获取o第一次出现的位置,将null单独处置,如果没有o返回-1,返回false
2.有的话调用remove().返回true
8.获取index位置上元素
public E get(int index){
rangeCheck(index);
E e=(E)array[index];
return e;
}
步骤:
1.检测下标是否异常
2.将下标index位置元素强转为E类型并返回
9.将index位置上的元素设置为e
public E set(int index,E e){
rangeCheck(index);
array[index]=e;
return e;
}
步骤:
1.检测下标是否异常
2.将index位置元素设置为e
3.返回e
10.清空
public void clear(){
for(int i=0;i<size;i++){
array[i]=null;
}
size=0;
}
将每个元素设置为null,size=0.
11.判断o是否在线性表中
public boolean contains(Object o){
return indexOf(o)>0;
}
其实就是判断o所在下标是否大于o,因为当时indexOf()不在时返回-1.
12.截取部分list
MyArrayList1<E> subList(int fromIndex,int toIndex){
if(toIndex-fromIndex<0){
throw new IllegalArgumentException("参数非法");
}
MyArrayList1<E> list=new MyArrayList1<>(toIndex-fromIndex);
for(int i=fromIndex;i<toIndex;i++){
list.add((E)array[i]);
}
return list;
}
步骤:
1.判断fromIndex和toIndex参数合法性
2.创建一个新列表用来保存截取后的列表
13.重写toString
@Override
public String toString(){
String s="[";
if(size>0){
for(int i=0;i<size-1;i++){
s+=array[i];
s+=",";
}
s+=array[size-1];
}
s+="]";
return s;
}
14.主方法
public static void main(String[] args) {
MyArrayList1<Integer> list=new MyArrayList1<>(3);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list);
System.out.println("长度为:"+list.size());
list.add(0,0);
System.out.println(list);
if(list.contains(5)){
list.add(5);
}
list.add(0);
System.out.println(list);
System.out.println(list.indexOf(0));
System.out.println(list.lastIndexOf(0));
list.remove(0);
System.out.println(list);
list.clear();
System.out.println(list);
}
}