Array 类
首先,以下两种方式都不能动态生成数组:
- 将
Object[]
强制转换为目标类型数组; - 使用
new T[]
语句。
但 java.lang.reflect
包下的 Array
类,提供了 newInstance()
方法,使得利用反射机制动态生成数组成为可能。
Array.newInstance()
Array.newInstance()
方法需要两个参数:数组元素类型和数组长度,方法声明如下所示:
public static Object newInstance(Class<?> componentType, int length) {...}
下面给出了两个示例,分别动态创建了一个 int
数组和一个 Integer
数组:
int[] ints = (int[]) Array.newInstance(int.class, 3);
Integer[] integers = (Integer[]) Array.newInstance(Integer.class, 3);
注意 Array.newInstance()
方法返回的是 Object
类型对象,所以需要显式转换返回结果(注意这里并不是强制类型转换)。
但上述示例并不能算是动态生成数组,顶多是对 Array.newInstance()
方法的调用,下面将利用泛型对代码进行改造。
使用泛型
我们可以使用泛型表示数组元素类型,并提供一个静态方法方便调用,示例代码如下所示:
public static <T> T[] createArray(Class<T> type, int length) {
return (T[]) Array.newInstance(type, length);
}
你也可以将泛型放置在类上,并将上面的静态方法改为一个非静态方法。
利用泛型,我们省去了将 Object
对象显式转换为目标类型数组的步骤,但这也引入了一个不容易发现的问题:如果调用此方式时,传入的是基本数据类型,则会报错。示例代码如下所示:
createArray(int.class, 3);
这个问题是由类型擦除引起的, createArray()
方法类型擦除后的代码如下所示:
public static Object[] createArray(Class<Object> type, int length) {
return (Object[]) Array.newInstance(type, length);
}
就本例而言, Array.newInstance(int.class, 3)
返回的虽然是一个 Object
对象,但实际上是一个 int[]
数组( Object
对象指向该数组),而 (Object[]) int[]
是非法的(可参考《强制类型转换》),这就导致了错误的发生。
那怎么解决这个问题呢?一种可行但看起来并不完美的方案是:利用 overload 机制,为每个基本数据类型添加一个 createArray()
方法。
由于 void.class 也能传入 createArray() 方法,所以还应添加代码首先排除这种情况。
Arrays.copyof()
Arrays
类提供的 copyOf()
方法也是通过上述方式实现的,源代码如下所示:
@SuppressWarnings("unchecked")
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
由于 copyOf()
方法传入的是数组,而非数组元素类型,所以首先需要利用 Class
类的 getComponentType()
获取数组元素类型,如代码的第 10 行所示。
另外也因为泛型类型擦除的原因, Arrays
类还提供了 8 个 overload copyOf()
方法。