封装一个ArrayBox--实际是ArrayList的底层简单实现

package arrayBox;

/**
 * 设计一个类,可以新增,删除,获取元素
 * 
 * @author my 数组存储数据 ArrayBox存储 int[] arr=new int[10] ArrayBox box=new Array()
 *         arr[0]=5 box.add(5);
 *         分析:作为用户而言,arraybox的好处是,1.不需关心索引,自动管理存在哪个位置,0号位置,或者1号位置
 *         。2.不需要关心长度,不用担心存不下
 * 
 */
public class ArrayBox<E>{//泛型
    private Object[] elementData;// 在box内部还是使用数组进行存储
    private int size = 0;// 记录有效元素个数
    private static final int DEFAULT_CAPACITY=10;//默认长度
    public ArrayBox(){
        elementData=new Object[DEFAULT_CAPACITY];
    }
    //这两个构造方法的作用是让用户可以自己使用默认的长度,或者自定义
    public ArrayBox(int capacity){
        elementData=new Object[capacity];
    }
    /**
     * 添加元素
     * 
     * @param element
     */
    public boolean add(E element) {
        // 添加元素之前,首先得确保可以存的下
        this.ensureCapacity(size+1);// 这里采用的是一个一个加的,所以需要的最小长度就是,原有效个数基础上加一个
        // 如果上面这句代码执行没问题,要么空间够,不需要扩容,直接在旧数组中插入一个元素,要么不够,进行扩容复制到新数组后,指向旧数组,再插入
        elementData[size++] = element;// 第一次是0号位置存储,并自增记录有效个数
        return true;// 返回true表示存储成功

    }
    /**
     * 获取元素
     * @param index
     * @return
     */
    public Object get(int index){
        //先检查index是否合法 >=0 <=size
        this.rangeCheck(index);
        return elementData[index];
    }
    /**
     * 删除元素
     * 需要删除的那个元素索引
     * return 删除的那个元素
     */
    public Object remove(int index) {
        this.rangeCheck(index);
        //先將index位置的旧值保存起来、
        Object oldValue=elementData[index];
        //删除的方法是遍历后一个元素覆盖前一个元素
        //10.20.30.40.50.60.0000
        //10 20 40 40 50 60 0000 
        //10 20 40 50 50 60 0000
        //10 20 40 50 60 60 0000
        //10 20 40 50 60 0  0000 
        /*这种写法会导致一个问题,就是如果有效元素个数刚刚填满数组,那么遍历最后一次将最后一个元素用有效元素之外的0覆盖时数组越界
        for(int i=index;i<size;i++){
            elementData[i]=elementData[i+1];
        }
        */
        for(int i=index;i<size-1;i++){
            elementData[i]=elementData[i+1];
        }
        elementData[--size]=0;//避免了上诉写法的数组越界,记录有效元素-1,并将最后一个元素,这里是60,替换为0
        return oldValue;//返回删除的元素给用户
        
    }
    private void rangeCheck(int index){
        if(index<0 || index>=size){
            throw new BoxIndexOutOfBoundsException();//new一个自定义的异常对象,把它抛出来
        }
    }


    /**
     * 确保容量够用,目前我们声明的数组是10个长度,那么得比较存入的长度是否超过10
     * 
     * @return
     */
    private void ensureCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0) {
            // 需要的最小长度比原数组长度还大,需要扩容
            this.grow(minCapacity);

        }

    }
    /**
     * 扩容
     * @param minCapacity
     */
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;// 原数组长度
        int newCapacity = oldCapacity + oldCapacity >> 1;// 这里扩容1.5倍。乘法不是乘以2的倍数,底层效率,位运算更高
        if (newCapacity - minCapacity < 0) {// 新计算得到的长度仍然比需要的最小长度小,那么直接赋值需要的最小长度作为新新数组长度
            newCapacity = minCapacity;
        }
        // 按照上面的计算得到一个newCapacity,创建一个新数组,将旧数组的东西全部复制到新数组,把旧数组的名字给新数组用
        this.elementData = this.copyOf(elementData, newCapacity);

    }
    /**
     * 创建一个新数组,将旧数组的值复制到新数组
     * @param oldArray
     * @param newCapacity
     * @return array
     */
    private Object[] copyOf(Object[] oldArray, int newCapacity) {
        Object[] newArray = new Object[newCapacity];
        for (int i = 0; i < oldArray.length; i++) {
            newArray[i] = oldArray[i];
        }
        return newArray;
    }

}
package arrayBox;


public class Test {

    public static void main(String[] args) {
        ArrayBox box =new ArrayBox();
        box.add(10);
    
    }

}

package arrayBox;
/**
 * 自定义异常类
 * @author my
 *
 */
public class BoxIndexOutOfBoundsException extends RuntimeException{
    public BoxIndexOutOfBoundsException(){
        
    }
    public BoxIndexOutOfBoundsException(String msg){
        super(msg);//调用父类的带参构造方法
    }
}
原文地址:https://www.cnblogs.com/hebiao/p/12564798.html