动态数组ArrayList的实现(添加缩容功能)

本文介绍了如何实现一个自定义的ArrayList类,包括初始化、增删改查等基本操作,并实现了动态扩容和缩容功能。在Student类中重写了equals和hashCode方法以支持对象的正确比较。测试类展示了ArrayList的使用,包括添加、查找和删除元素,以及清空后的缩容操作。

ArrayList

public class ArrayList<E>  {
    //数组大小
    private int size=0;
    //元素数组
    private E[] elements;
    //常量
    private static final int DEFAULT_CAPACITY=10;
    private static final int ELEMENT_NOT_FOUND=-1;

    public ArrayList(int capacity){
        capacity= Math.max(capacity, DEFAULT_CAPACITY);
        elements = (E[]) new Object[capacity];
    }

    public ArrayList(){
        this(DEFAULT_CAPACITY);
    }

    /**
     * 返回动态数组大小
     * @return
     */
    public int size(){
        return size;
    }

    /**
     * 是否为空
     * @return
     */
    public boolean isEmpty(){
        return size==0;
    }

    /**
     * 是否包含element元素
     * @param element
     * @return
     */
    public boolean contains(E element){
        return indexOf(element)!=ELEMENT_NOT_FOUND;
    }

    /**
     * 返回element元素(可以为空)在动态数组中的索引,不存在则返回-1
     * @param element
     * @return
     */
    public int indexOf(E element){
        //对null讨论,防止空指针异常
        if(element==null){
            for (int i = 0; i < size; i++)
                if(elements[i]==null)return i;
        }
        for(int i=0;i<size;i++)
            if(element.equals(elements[i]))return i;//调用element的equals方法
        return ELEMENT_NOT_FOUND;
    }

    /**
     * 清空所有元素
     */
    public void clear(){
        //清空存储的所有对象的地址,等待JVM进行垃圾回收
        for (int i = 0; i < size; i++) {
            elements[i]=null;
        }
        size=0;
    }

    /**
     * 将element插入到数组末端
     * @param element
     */
    public void add(E element){
        add(size,element);
    }

    /**
     * 将element插入到索引index位置
     * @param index
     * @param element
     */
    public void add(int index,E element){
        //可以传入空值
        rangeCheckForAdd(index);
        ensureCapacity(size+1);//确保有size+1的存储空间
        //使用arraycopy更快
        //System.arraycopy(elements,index,elements,index+1,size-index);
        for(int i=size-1;i>=index;i--)
            elements[i+1]=elements[i];
        elements[index]=element;
        size++;
    }

    /**
     * 删除索引为index处的元素
     * @param index
     * @return 被删除的元素
     */
    public E remove(int index){
        rangeCheck(index);
        //保存被删除元素
        E old=elements[index];
        for(int i=index+1;i<size;i++)
            elements[i-1]=elements[i];
        //将最后一个对象的地址清空
        elements[--size]=null;
        return old;
    }

    /**
     * 获取索引为index处的元素
     * @param index
     * @return
     */
    public E get(int index){
        rangeCheck(index);
        return elements[index];
    }

    /**
     * 将index处的元素修改为element
     * @param index
     * @param element
     * @return 被替换的元素
     */
    public E set(int index,E element){
        rangeCheck(index);
        E old=elements[index];
        elements[index]=element;
        return old;
    }

    /**
     * 打印格式为size:x [e1, e1, .., en]
     * @return
     */
    @Override
    public String toString() {
        //使用StringBuilder进行字符串的拼接更加高效
        StringBuilder sb=new StringBuilder();
        sb.append("size:").append(size).append(" [");
        for(int i=0;i<size;i++){
            if(i!=0)
                sb.append(", ");
            sb.append(elements[i]);
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * 抛出索引越界异常
     * @param index
     */
    private void throwException(int index){
        throw new IndexOutOfBoundsException("index:"+index+" , size:"+size);
    }

    /**
     * 判断索引的合理性
     * @param index
     */
    private void rangeCheck(int index){
        if(index<0||index>=size)
            throwException(index);
    }

    //为Add方法检查索引合理性
    private void rangeCheckForAdd(int index){
        if(index<0||index>size)//对于Add方法可以在size处添加元素
            throwException(index);
    }

    //检查容量是否足够
    private void ensureCapacity(int capacity){
        if(capacity<elements.length)return;
        int oldCapacity=elements.length;
        int newCapacity=oldCapacity+(oldCapacity>>1);//新建数组,扩容1.5倍
        E[] newElements=(E[]) new Object[newCapacity];
        for(int i=0;i<size;i++)//复制数据,可用arraycopy
            newElements[i]=elements[i];
        elements=newElements;//将新数组地址赋给记录原数组的变量elements
        System.out.println(oldCapacity+"扩容为"+newCapacity);
    }

}

新建Student类,重写equals、hashCode方法

import java.rmi.StubNotFoundException;

public class Student {
    private String name;
    private int id;

    public Student() {
    }

    public Student(String name, int id) {
        setName(name);
        setId(id);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        if(id<0)
            throw new IllegalArgumentException("id不能小于0");
        else
            this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        if(this==obj)return true;
        if(obj.getClass()!=Student.class||null==obj)return false;
        Student stu=(Student) obj;
        if(id!=stu.getId())return false;
        return name!=null?name.equals(stu.getName()):stu.getName()==null;
    }

    @Override
    public int hashCode() {
        int result=name!=null?name.hashCode():0;
        result=result*31+id;
        return result;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
    
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("对象被回收");
    }
}

测试类

public class ArrayTest {
    public static void main(String[] args) {
        ArrayList<Student> list=new ArrayList<>();
        list.add(new Student("James1",1));
        list.add(new Student("James2",2));
        list.add(list.size(),new Student("Jack",3));
        list.add(null);
        System.out.println(list);
        Student James2=new Student("James2",2);
        int index=list.indexOf(James2);
        System.out.println(index);
        //查找空值索引
        System.out.println(list.indexOf(null));
        list.clear();
        //提醒JVM进行垃圾回收
        System.gc();
    }
}

缩容

如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑进行缩容操作。
此时需要修改remove方法:

/**
     * 删除索引为index处的元素
     * @param index
     * @return 被删除的元素
     */
    public E remove(int index){
        rangeCheck(index);
        //保存被删除元素
        E old=elements[index];
        for(int i=index+1;i<size;i++)
            elements[i-1]=elements[i];
        //将最后一个对象的地址清空
        elements[--size]=null;
        trim();//缩容操作
        return old;
    }
private void trim(){
      int oldCapacit=elements.length;
      int newCapacity=oldCapacit >>1;
      if(size>newCapacity||newCapacity<DEFAULT_CAPACITY)return;
      //当数据量小于容量的1/2,缩容1/2
      E[] newElements=(E[]) new Object[newCapacity];
      for(int i=0;i<size;i++)
          newElements[i]=elements[i];
      elements=newElements;
      System.out.println(oldCapacit+"缩容为"+newCapacity);  
}

此外当进行clear()清空操作后,也可以进行缩容:

/**
* 清空所有元素
*/
public void clear(){
    //清空存储的所有对象的地址,等待JVM进行垃圾回收
    for (int i = 0; i < size; i++) {
        elements[i]=null;
    }
    size=0;
    //当数组被使用后情况且内存大小大于默认容量,缩容
    if(elements!=null&&elements.length>DEFAULT_CAPACITY)
        elements= (E[]) new Object[DEFAULT_CAPACITY];
}

测试代码:

public class ArrayList2Test {
    public static void main(String[] args) {
        ArrayList2<Integer> arrayList2=new ArrayList2<>();
        for(int i=0;i<30;i++)
            arrayList2.add(i);
        System.out.println(arrayList2);
        for(int i=0;i<25;i++)
            arrayList2.remove(0);
        System.out.println(arrayList2);
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值