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);//调用父类的带参构造方法
}
}