数组的缺点在于:长度一旦确定就不可改变;不能删除元素;操作不当可能会产生数组越界问题等。
我们利用java语言来进行ArrayBox类的设计,以此去体会面向对象的编程思想。
ArrayBox类从一定的角度来看可以完成数组存取元素的功能,同时还解决了使用数组带来的一些缺陷,让容器来做更多的事,让元素的增加,删除,遍历都变得简单可靠。
ArrayBox.java
public class ArrayBox<E> {
private static final int DEFAULT_CAPACITY = 10;
private Object[] elementData;
private int size = 0;//记录有效元素的个数
public ArrayBox(int capacity) {
elementData = new Object [capacity];
}
public ArrayBox() {
elementData = new Object [DEFAULT_CAPACITY];
}
public boolean add(E element){//E是创建ArrayBox对象时规定的类型
this.ensureInternalCapacity(size+1);
//如果上面一行代码可以执行完毕,证明数据可以存储成功
// elementData[size] = element;
// size++;这两句可以合并为一句
elementData[size++] = element;//因为size的自增是后执行的
return true;
}
private void ensureInternalCapacity(int minCapacity){
if(minCapacity - elementData.length>0){
//需要的最小容量比总容量还要大,装不下
this.grow(minCapacity);
}
}
//扩容,计算出一个合理的长度newCapacity
private void grow(int minCapacity){
int oldCapacity = elementData.length;
// oldCapacity>>1 右位移表示除以2的1次幂
int newCapacity = oldCapacity + (oldCapacity>>1);
//如果扩容后空间还是不够,那么直接使用所需空间作为我的容量
if(newCapacity - minCapacity <0){
newCapacity = minCapacity;
}
elementData = this.copyOf(elementData, newCapacity);
//经过一番计算,最终获取到一个合理的长度newCapacity
}
//将旧数组的元素全部移入新数组内,需要旧数组和新数组的长度
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;
}
public E get(int index){
//检测index是否合法 大于等于0 &&小于size
this.rangeCheck(index);//如果抛出异常,程序会异常终止
return (E)elementData[index];
}
private void rangeCheck(int index){
if(index<0 || index>=size){
//通过异常来告知用户index不合法
throw new ArrayBoxIndexOutOfBoundsException("index is "+index+" but size only is "+size);
}
}
public E remove(int index){
this.rangeCheck(index);
E oldObject = (E)elementData[index];
for (int i = index; i < size-1; i++) {
elementData[i] = elementData[i+1];
}
// elementData[size-1] = 0;
// size--;
elementData[--size] = null;
return oldObject;
}
public int getSize() {
return size;
}
}
ArrayBoxIndexOutOfBoundsException.java
public class ArrayBoxIndexOutOfBoundsException extends RuntimeException{
public ArrayBoxIndexOutOfBoundsException(){
}
public ArrayBoxIndexOutOfBoundsException(String msg){
super(msg);//msg提供给父类
}
}
总结以上程序中注意的点:
- 使用java的泛型的可以使得我们设计的集合能够存取引用数据类型。
- 使用常量DEFAULT_CAPACITY可以增强代码的可读性。
- 使用有参的构造方法可以使得集合内置的数组初始容量可以人为规定,使用起来更加灵活。
- 采用位移来计算2次幂可提高程序的计算效率。