Array 类

首先,以下两种方式都不能动态生成数组:

  • Object[] 强制转换为目标类型数组;
  • 使用 new T[] 语句。

java.lang.reflect 包下的 Array 类,提供了 newInstance() 方法,使得利用反射机制动态生成数组成为可能。

Array.newInstance()

Array.newInstance() 方法需要两个参数:数组元素类型和数组长度,方法声明如下所示:

  1. 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() 方法。