数组
- 数组是一种顺序存储的线性表,所有元素的内存地址都是连续的
int[] array = new int[]{11, 12, 13} - 在很多情况下我们定义了数组的长度后,便不能更改数组的长度,但我们确希望的数组的长度是能够动态变换的
动态数组的接口设计
- 创建ArrayList类,定义size属性来管理数组中元素的个数,定义elements(一个数组变量)属性来管理存取的数据
- 按照Java接口的设计思想,定义一些方法(即对数组的增删改查操作)
动态数组的实现
private int size; //记录数组的长度
private E[] elements; //用于存取数据的底层数组
//设置elements数组的默认初始化空间
private static final int CAPACITY_DEFAULT = 10;
//设置未找到变量时的默认值
private static final int ELEMENT_NOT_FOUND = -1;
//设置带参构造器
public ArrayList(int capacity) {
capacity = Math.max(capacity, CAPACITY_DEFAULT);
elements = (E[]) new Object[capacity];
}
//设置空参构造器,即:不自定义数组的长度
public ArrayList() {
this(CAPACITY_DEFAULT);
}
/**
* 一、数组元素的添加
* 添加元素方法:
* 分为两种情况:
* 1.在最后一个元素的后面添加新的元素:只需将elements[size] = element,然后size加1即可
* 2.在中间部位添加元素;需要将index只后的元素进行后移,注意:在移动前需要判断数组是否越界
* @param index 添加元素索引
* @param element 添加的元素
*/
public void add(int index, E element) {
//判断越界
rangeCheckForAdd(index);
//判断是否需要扩容
ensureCapacity();
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
}
/**
* add()重载方法:如果不指定索引,即:默认向最后位置添加元素
*/
public void add(E element) {
add(size, element);
}
/**
* 添加元素前需要判断索引是否越界,注意索引不能小于0,也不能大于size
* @param index 添加元素的索引
*/
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds();
}
}
/**
* 二、数组越界
* 数组越界抛出的异常信息
*/
private void outOfBounds() {
throw new IndexOutOfBoundsException("索引越界");
}
/**
* 三、数组扩容
* 用来保证数组的长度是否还够(动态数组的核心-->数组扩容)
*/
private void ensureCapacity() {
//获取数组当前容量
int oldCapacity = elements.length;
//如果当前储存元素个数 < 当前数组容量,直接返回
if (size < oldCapacity) return;
//新数组的容量是原数组的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//创建新数组
E[] newElements = (E[]) new Object[newCapacity];
//原数组中的数据储存到新数组中
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
//引用新数组
elements = newElements;
}
/**
* 四、数组元素删除
* 删除元素时需要判断元素索引是否越界,即不能小于0,也不能大于等于size
* 删除元素时只需用后一位元素覆盖前一位元素
* 注意:思考最后一个元素怎么处理:只需最后一个元素复位空
*/
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; //--size既让数组长度减一又可以代表老数组的最后一个元素
//将数组元素返回
return old;
}
/**
* 为删除元素服务的检查操作
*/
public void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds();
}
}
/**
* 五、清空数组
* 清空数组:只需所有元素的地址设为null, size设为0即可
*/
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
/**
* 六、设置元素
* 修改元素:只需将该位置元素取出替换即可,同时需要注意判断索引是否越界
* @return 返回被替换元素
*/
public E set(int index, E element) {
//判断元素是否越界
rangeCheck(index);
//取出被替换的元素
E oldElement = elements[index];
//替换元素
elements[index] = element;
//返回被替换元素
return oldElement;
}
/**
* 七、查询元素
* 查询元素,只需要将指定索引的元素返回,注意索引是否越界即可
* @return 返回查出元素
*/
public E get(int index) {
//判断是否越界
rangeCheck(index);
return elements[index];
}
/**
* 八、获取元素索引
* 可以通过循环, 查找元素在数组中的位置
* 注意:假如数组中可以存储null,而null是不能调用equals方法的,所以需要对传入的元素进行判断,如果查找的元素是null
* ,需要单独处理。
* @return 返回索引或-1
*/
public int indexOf(E element) {
if (element == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == null) return i;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(elements[i])) return i;
}
}
return ELEMENT_NOT_FOUND;
}
/**
* 九、判断元素是否为空
* 只需判断索引是否为ELEMENT_NOT_FOUND
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
/**
* 十、获取数组数量
* @return size的值,即为元素的数量
*/
public int size() {
return size;
}
/**
* 十一、判断数组是否为空
* @return 通过判断size的值是否为0即可判断数组是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 十二、打印数组
* 自定义如何输入动态数组
*/
public String toString() {
StringBuilder string = new StringBuilder();
string.append("size = ").append(size).append(", [");
for (int i = 0; i < size; i++) {
if (i != 0) {
string.append(",");
}
string.append(elements[i]);
}
string.append("]");
return string.toString();
}