在Java中,数组是一种非常基础且重要的数据结构,它可以存储多个相同类型的元素。然而,数组的长度是固定的,一旦创建就无法改变,这给我们的开发带来了一些限制。为了解决这个问题,我们可以使用泛型来实现动态扩容的数组,即在数组元素达到上限时,自动创建一个更大容量的新数组并将原数组元素复制过去。本文将详细介绍如何使用泛型数组实现动态扩容和元素操作,并提供一些注意事项和相关知识。
import java.sql.Array;
import java.util.Arrays;
// 泛型: 类型模板 类名的后面 <E> 表示一个类型
// 泛型不能创建对象 不能new
public class MyArray<E> {
Object[] values;
int size;
int length;
public MyArray(int initLength) {
if (initLength <= 1) {
throw new IllegalArgumentException("不合法的参数");
}
values = new Object[initLength];
size = 0;
length = initLength;
}
private void grow(int min) {
int oldLength = length;
int newLength = oldLength + (oldLength >> 1);
if (newLength < oldLength + min) {
oldLength = oldLength + min;
newLength = oldLength + (oldLength >> 1);
}
Object[] newValues = new Object[newLength];
for (int i = 0; i < values.length; i++) {
newValues[i] = values[i];
}
values = newValues;
length = newLength;
System.out.println("扩容后的长度:" + length);
}
public void add(E e) {
if (size == length) {
grow(1);
}
values[size++] = e;
}
public void addAll(E[] e) {
if (size + e.length >= length) {
int min = e.length - (length - size);
grow(min);
}
for (int i = 0; i < e.length; i++) {
values[size++] = e[i];
}
}
public E get(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("传入下标索引越界");
}
return (E) values[index];
}
public E remove(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("传入下标索引越界");
}
E old = (E) values[index];
for (int i = index; i < size - 1; i++) {
values[i] = values[i + 1];
}
size--;
values[size] = null;// 清除最后一个
return old;
}
// 移除多个
public int removeEle(E e) {
int count = 0;
for (int i = 0; i < size; i++) {
if (values[i].equals(e)) {
count++;
remove(i);
}
}
return count;
}
public void removeAll(int si, int ei) {
if (si < ei && si >= 0 && ei < size) {
for (int i = si; i <= ei; i++) {
if ((ei + i) < size) {
values[i] = values[ei + i];
} else {
values[i] = null;
}
}
size -= (ei - si);
}
}
// 排序
public static void main(String[] args) {
MyArray myArray = new MyArray(10);
for (int i = 0; i < 150; i++) {
myArray.add(i);
myArray.add("hello");
myArray.add(1.2 * i);
}
Object[] objects = new Object[160];
for (int i = 0; i < objects.length; i++) {
objects[i] = i + 100;
}
// myArray.addAll (objects);
// System.out.println ((163 + 147) + (163 + 147) / 2);
myArray.removeAll(2, 100);
System.out.println(Arrays.toString(myArray.values));
// 定义在类上的时候 就是一个符号 表示一种类型
// 创建对象时指代具体的类型
MyArray<String> strList = new MyArray<>(10);
for (int i = 0; i < 5000; i++) {
strList.add("Hello" + i);
// strList.add (i);
}
String str = strList.get(50);
System.out.println(str);
}
}
代码解析: 上述代码是一个名为MyArray的泛型类,它实现了动态扩容和元素操作的功能。以下是代码的主要部分:
-
构造函数:通过传入初始长度来创建MyArray对象,如果初始长度小于等于1,则抛出IllegalArgumentException异常。
-
动态扩容:当数组元素达到上限时,调用grow()方法进行扩容。该方法会根据算法计算出新数组的长度,并将原数组元素复制到新数组中。
-
添加元素:add()方法用于向数组中添加元素。如果数组已满,则先调用grow()方法进行扩容,然后将元素添加到数组末尾。
-
批量添加元素:addAll()方法用于从一个数组中批量添加元素到当前数组。如果当前数组的容量不足以容纳所有元素,则先调用grow()方法进行扩容,然后将元素逐个添加到数组末尾。
-
获取元素:get()方法用于根据索引获取数组中的元素。如果索引越界,则抛出ArrayIndexOutOfBoundsException异常。
-
删除元素:remove()方法用于根据索引删除数组中的元素。如果索引越界,则抛出ArrayIndexOutOfBoundsException异常。删除元素后,将后续元素向前移动一个位置,并将最后一个位置置为null。
-
批量删除元素:removeEle()方法用于删除数组中与指定元素相等的所有元素,并返回删除的数量。
-
区间删除元素:removeAll()方法用于删除数组中指定索引范围内的元素。删除元素后,将后续元素向前移动,同时将末尾位置设为null。
-
示例:代码的末尾给出了使用示例,展示了如何创建MyArray对象、添加元素、扩容、删除元素等操作。
注意事项和知识:
-
泛型数组的创建:在Java中,我们不能直接创建泛型数组,因此我们使用Object类型数组来代替。这样做的原因是Java的泛型是在编译期进行类型擦除的,编译后的字节码中不包含泛型的信息。因此,在数组中使用泛型时,会出现警告信息。
-
类型转换:在代码中,我们使用强制类型转换将Object类型转换为泛型类型。需要注意的是,在进行强制类型转换时,要确保类型的兼容性,否则可能会引发ClassCastException异常。
-
动态扩容的思路:在MyArray类中,我们定义了一个动态扩容的方法grow()。该方法根据算法计算出新数组的长度,并将原数组元素复制到新数组中。常见的扩容算法是每次扩容增加当前数组长度的一半。
-
索引越界检查:在操作数组元素时,需要进行索引越界检查。如果索引超出了有效范围,可以通过抛出ArrayIndexOutOfBoundsException异常来提示错误。
-
删除元素的维护:在删除元素后,需要将后续元素向前移动一个位置,并将最后一个位置置为null。这样可以确保数组的连续性,并避免悬空引用导致内存泄漏。
-
批量删除元素的效率:在removeEle()方法中,我们使用循环逐个删除与指定元素相等的所有元素。这种方法的时间复杂度为O(n^2),对于大量元素的情况下,效率较低。如果需要高效删除大量元素,可以考虑使用其他数据结构,如链表或集合。
-
泛型类型推断:在代码示例中,我们使用了菱形操作符<>来进行泛型类型推断。这种写法可以简化代码,并提高可读性。
总结: 通过使用泛型数组实现动态扩容和元素操作,我们可以更灵活地处理数据,并提高代码的可维护性和可复用性。在实际开发中,我们需要注意泛型数组的创建方式、类型转换的安全性、索引越界的检查以及删除元素后的维护等问题。同时,对于大量元素的批量删除操作,需要考虑选择合适的数据结构来提高效率。希望本文对于理解泛型数组的实现和相关知识有所帮助。