封装一个自己的动态数组
我们都知道java的数组在创建时,不管是动态初始化还是静态初始化,数组在创建完毕之后,数组容量不能改变。这显然不能满足用户的需求,我们可以试着使用java的数组封装一个自己的动态数组类,随着添加删除元素,可以实现动态数组容量的缩放。
封装一个动态数组的新功能:
- 实现普通数组做不到的强大的增删查改
- 使用泛型,可以放入不同类型的元素
- 数组容量随实际元素动态改变
话不多说,上代码(talk is cheap show me the code)
/*
* 封装一个自己的动态数组,实现增删查改
* */
public class MyArray<T> {
// 泛型数组
private T[] data;
// 数组中实际存放元素个数,指向第一个未使用数组元素
private int size;
// 数组的最大容量,没有必要,可以用data.length替代
// private int capacity;
/*
* 一个带参构造和一个无参构造
* */
public MyArray(int capacity) {
// 不可以直接new T[capacity]
this.data = (T[]) new Object[capacity];
//构造初始化
size = 0;
}
public MyArray() {
//不知道创建多大数组,默认数组长度为10
this(10);
}
/*
* 数组的扩容缩容方法,作为动态数组的功能性方法,供其他方法调用,使用private修饰
*/
private void resize(int newCapacity) {
T[] newData = (T[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
/*
* 添加元素:在index位置添加元素e
* */
public void add(int index, T e) {
if (index < 0 || index > size){
throw new IndexOutOfBoundsException("插入失败,索引不在数组实际范围内");
}
if (size == data.length) {
resize(2 * data.length);
}
//在插入位置后的数组元素依次往后挪,并且是从右向左循环,防止前面元素覆盖
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = e;
size++;
}
public void addFirst(T e){
add(0,e);
}
public void addLast(T e){
add(size,e);
}
/*
* 删除元素:删除索引为index位置的元素,并返回被删除的元素值
* */
public T remove(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("删除失败,索引不在数组实际范围内");
}
T num = data[index];
for (int i = index; i < size-1; i++) {
data[i] = data[i + 1];
}
size--;
//防止复杂度震荡,不急于对数组缩容,只有实际元素小于容量的1/4才缩容为原来的1/2
if (size == data.length / 4 && data.length / 2 != 0){
resize(data.length / 2);
}
return num;
}
public T removeFirst() {
return remove(0);
}
public T removeLast() {
return remove(size - 1);
}
/*
* 查找元素:get方法保证了只能获取到实际存储元素,无法查询没使用数组元素,保证数据安全,保证了封装性
* */
public T get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("获取失败,索引不在数组实际范围内");
}
return data[index];
}
public T getFirst (){
return get(0);
}
public T getLast (){
return get(size-1);
}
/*
* 动态数组是否包含某个元素
* */
public boolean contains(T e) {
for (int i = 0; i < size; i++) {
if (data[i] == e) {
return true;
}
}
return false;
}
/*
* 查找元素索引:查找数组中元素e所在索引,如果不存在元素e,(非法索引)则返回-1
* */
public int find(T e) {
for (int i = 0; i < size; i++) {
if (data[i] == e) {
return i;
}
}
return -1;
}
/*
* 获取动态数组实际元素个数:
* */
public int getSize() {
return size;
}
/*
* 获取动态数组容量
* */
public int getCapacity() {
return data.length;
}
/*
* 动态数组非空判断
* */
public boolean isEmpty() {
// if(size==0){
// return true;
// }else {
// return false;
// }
return size == 0;
}
/*
* 修改更新 动态数组元素
* */
public void set(int index, T e) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("更新失败,索引不在数组实际范围内");
}
data[index] = e;
}
@Override
//这个override注解很有用,防止重写时方法名,参数错误以至于没有重写父类方法
public String toString() {
StringBuilder s = new StringBuilder();
//String.format为格式化字符串
s.append(String.format("Array's size=%d,capacity=%d\n", getSize(), getCapacity()));
s.append("[");
//这里只输出实际元素,空余元素不输出
for (int i = 0; i < size; i++) {
if (i != size - 1) {
s.append(data[i]);
s.append(",");
} else {
s.append(data[i]);
}
}
s.append("]");
//将StringBuilder转化为String类型
return s.toString();
}
/*
* 测试
* */
public static void main(String[] args) {
MyArray<Integer> myArray=new MyArray<>();
for (int i = 0; i < 20; i++) {
myArray.addLast(i);
System.out.println(myArray);
}
for (int i = 0; i < 20; i++) {
myArray.removeFirst();
System.out.println(myArray);
}
}
}