Java中的小知识 --- 集合(三)之ArrayList可变长数组

特征:

数组形式的操作方式,查询效率高,但是删除增加效率低

底层是一个数组形式,数组:

Object类型数组

方法:

ArrayList中使用的方法基本上都是从List接口中遵从实现的方法.
特征:
    ensureCapacity(int minCapacity);
        判断当前容量是否足够
    trimToSize();
        截断整个数组容量 ==> size有效元素个数,有的位置可能没保存元素但还是占用了空间,
        所以阶段之后每个位置都有元素,不会有白白占用空间的问题出现;
        时间换空间,空间换时间
Constructor构造方法:
    add(E e);
    add(int index, E e);
    addAll(自定义ArrayList<E> e);
    addAll(int index, 自定义ArrayList<E> e);
    remove(Object obj);
    remove(int index);
    set(int index, E);
    E get(int index);
    int indexOf();
    int lastIndexOf();
    boolean contains(Object obj);
    boolean containsAll(自定义ArrayList类型 list);
    boolean isEmpty();
    int size();
    自定义ArrayList subList(int fromIndex, int endIndex);
    Object[] toArray();

方法实现:

package com.wcc.d_arraylist;

import java.util.Arrays;

/**
 * @Author kk
 * @Date 2020/3/16 18:42
 */
public class MyArrayList<E> {

    /**
     * 准备一个底层数组,用于存储数据内容
     */
    private Object[] elements;
    /**
     * 初始化默认容量
     */
    private static final int DEFAULT_CAPACITY = 10;
    /**
     * 最大数组容量 , -8是为了腾出一定的空间,保存数组的必要内容
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    /**
     * 当前底层数组中保存的有效元素的个数
     */
    private int size = 0;

    /**
     * 无参构造方法,但是需要提供给数组一个初始化容量来保存必要的数据
     */
    public MyArrayList(){
        elements = new Object[DEFAULT_CAPACITY];
    }

    /**
     * 用户指定保存元素容量的初始化过程,要求用户指定的容量范围是有效的
     * @param initCapacity 用户指定的初始化容量,但是不饿能小于0不能大于MAX_ARRAY_SIZE
     */
    public MyArrayList(int initCapacity){
        if(initCapacity <0 || initCapacity > MAX_ARRAY_SIZE){
            throw new IllegalArgumentException("IllegalArgumentException:" + initCapacity);
        }
        elements = new Object[initCapacity];
    }
    /**
     * 增加方法
     */
    /**
     * 添加元素到当前集合的末尾
     * @param e 要求是符合泛型约束的指定数据类型
     * @return 添加成功返回true
     */
    public boolean add(E e){
        //直接调用在指定下标位置添加元素的方法,只不过这里指定下标位置就是尾插法下标位置
        return add(size, e);

    }

    /**
     * 在底层数组的指定下标位置保存对应元素
     * @param index 指定下标位置,不能超出有效范围,0《=index《=size
     * @param e  符合泛型约束的数据类新
     * @return 添加成功返回true
     */
    public boolean add(int index, E e){
        //下标合法性判定
        if(index < 0 || index > size){
            throw new ArrayIndexOutOfBoundsException(index);
        }
        ensureCapacity(size + 1);
        for(int i = size - 1; i> index; i--){
            elements[i + 1] = elements[i];
        }
        elements[index] = e;
        size += 1;
        return  true;
    }
    /*
     * addAll方法
     *  1.需要得到添加集合中的元素内容,有效元素个数
     *  2.确认容量问题
     *  3.size = oldSize + newSize
     */

    /**
     * 添加另一个集合到当前集合的末尾
     * @param list MyArrayList类型,自定义ArrayList,要求存储元素和当前集合一致,或者是其子类
     * @return 添加成功返回true添加失败返沪false
     */
    public boolean addAll(MyArrayList<? extends E> list){
        Object[] array = list.toArray();
        int newSize = array.length;
        //size是原数组容量,newSize是要添加的数组的容量
        ensureCapacity(size + newSize);
        //elements.length是扩容后的数组容量
        for(int i = 0; i<newSize; i++){
            //array尾插法到原数组之后
            elements[i + size] = array[i];

        }
        return true;
    }
    public boolean addAll(int index, MyArrayList<? extends E> list){
        //这个方法没写完
        return true;
    }

    /**
     * 删除指定元素
     * @param obj 要删除的元素
     * @return 删除成功返回true
     */
    public boolean remove(Object obj){
        //获取要删除的元素的下标
        int index = indexOf(obj);
        //调用下面的remove方法,删除该下标的元素
        //如果删除成功,下面的remove方法返回对应元素,然后null != 元素该方法返回值为true
        //如果删除失败返回null,然后null != null 该方法返回值为false
        return null != remove(index);
    }

    /**
     * 删除指定下标元素
     * @param index 
     * @return 删除成功返回对应元素,删除失败返回null
     */
    public E remove(int index){
        if( -1 == index){
            return null;
        }

        E e = get(index);

        for (int i = index; i< size; i++){
            elements[i] = elements[i + 1];
        }
        elements[size - 1] = null;
        size -= 1;

        return  e;
    }

    /**
     * 查询指定下标的元素
     * @param index 指定的下标,但是不能超出有效下标
     * @return 返回元素
     */
    @SuppressWarnings("unchecked")
    public E get(int index){

        if(index < 0|| index > size){
            throw new ArrayIndexOutOfBoundsException(index);
        }
        //该方法返回的是E类型,而element数组是Object类型,所以需要做一个强转
        return (E) elements[index];
    }

    /**
     * 替换指定下标的元素
     * @param index 指定的下标,但是必须在有效范围内
     * @param e 要替换的元素,符合泛型约束
     * @return 被替换的元素
     */
    public E set(int index, E e){
        if(index <0 || index > size){
            throw new ArrayIndexOutOfBoundsException(index);
        }
        //获取指定下标的元素
        E temp = get(index);
        //替换
        elements[index] = e;
        return temp;

    }

    /**
     * 判断指定元素是否存在
     * @param obj 需要判断的元素
     * @return 存在返回true 不存在返回false
     */
    public boolean contains(Object obj){
        //根据indexOf方法来判断元素是否存在,如果元素存在,indexOf方法就会返回
        //该元素第一次的下标位置,肯定大于-1,然后返回true
        //如果不存在,indexOf返回-1,等于-1,返回false
        return indexOf(obj) > -1;
    }

    /**
     * 判断指定list集合是否是原集合的子集合
     * @return
     */
    public boolean containsAll(){


        return true;
    }

    /**
     * 判断集合是不是空集合
     * @return 如果为空返回true,否则返回false
     */
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 获取集合中有效元素的个数
     * @return 有效元素个数
     */
    public int size(){
        return size;
    }

    /**
     * 获取当前集合的子集合,要头不要尾
     * @param fromIndex fromIndex <= endIndex,但是不得小于0截取开始的位置
     * @param endIndex endIndex >= fromIndex,小于等于size,截取结束的位置
     * @return 截取得到的MyArrayList子集合对象
     */
    MyArrayList<E> subList(int fromIndex, int endIndex){
        if(fromIndex > endIndex || fromIndex < 0 || endIndex > size){
            throw  new ArrayIndexOutOfBoundsException();
        }
        MyArrayList<E> listTemp = new MyArrayList<>(endIndex - fromIndex);
        for(int i = fromIndex; i < endIndex; i++){
            listTemp.add(this.get(i));
        }
        return listTemp;

    }

    /**
     * 查询指定元素在集合中第一次出现的下标位置
     * @param obj 指定的元素
     * @return 返回值大于等于0表示找到元素,否则返回-1
     */
    public int indexOf(Object obj){
       int index = -1;
       for(int i = 0; i < size; i++){
           if(obj.equals(elements[i])){
               index = i;
               break;
           }
       }
       return index;
    }

    /**
     * 查询指定元素在集合中最后一次出现的下标位置
     * @param obj 指定的元素
     * @return 返回值大于等于0表示找到元素,否则返回-1
     */
    public int lastIndexOf(Object obj){
        int index = -1;
        for(int i = size - 1; i >= 0; i--){
            if(obj.equals(elements[i])){
                index = i;
                break;
            }
        }
        return index;
    }
    /**
     * 返回MyArrayList集合中所有有效元素的Object数组
     * @return 包含集合所有元素的Object类型数组
     */
    public Object[] toArray(){
        //size 是有效元素个数,通过该方法可以获得一个只有当前数组中有效元素个数的数组
        return Arrays.copyOf(elements,size);
    }
    /*
     * 这里需要一个类内可以使用的用于判定当前容量是否满足添加要求的方法
     * 如果满足直接进入添加模式,如果不满足就执行grow方法,完成底层数组的扩容问题
     */

    /**
     * 每一次添加元素,都需要进行容量判断,如果满足可以进行添加操作,不满足需要执行grow方法
     * @param minCapacity 要求的最小容量
     */
    private void ensureCapacity(int minCapacity){
        if(minCapacity > elements.length){
            grow(minCapacity);
        }
    }

    /**
     * 底层数组的扩容方法,原理是创建新数组,移植数据,保存数组新地址
     * @param minCapacity 要求的最小容量
     */
    private void grow(int minCapacity){
        //1.获取原数组容量
        int oldCapacity = elements.length;

        //2.计算得到新数组容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //oldCapacity >> 1 就是oldCapacity除以2

        //3.判断新数组容量是否满足要求
        if(newCapacity < minCapacity){ //代表容量不足,新数组容量还没有达到最小的数组容量要求
            newCapacity = minCapacity;
        }
        //新数组容量是大于允许的最大数组容量
        if(newCapacity > MAX_ARRAY_SIZE){
            //二次判断minCapacity是否小于MAX_ARRAY_SIZE
            if(minCapacity < MAX_ARRAY_SIZE){
                //最小要求是不大于MAX_ARRAY_SIZE,代码可以运行
                newCapacity = minCapacity;
            } else{
                throw new OutOfMemoryError("Overflow MAX_ARRAY_SIZE");
            }

        }
        //4.使用数组工具类方法完成操作
        elements = Arrays.copyOf(elements, newCapacity);
    }

}
发布了28 篇原创文章 · 获赞 39 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42597414/article/details/104895784