今天我们聊一聊java.lang.reflect包下的Array类,重点关注其中的newInstance方法。
1、Array类的简单使用
java.lang.reflect包下除了提供Method(方法)、Constructor(构造器)、Filed(成员变量)这三个类,还提供了Array类,Array对象可以代表所有的数组,可通过Array类来动态创建数组,该类提供了以下类方法:
- static Object newInstance(Class<?> componentType, int... dimensions):创建指定元素类型、指定维度的数组。这里的dimensions是可变个数的。
- static xxx getXxx(Object arr, int index):返回arr数组的第index位置元素。这里xxx表示基本数据类型,比如getChar,getInt;若数组元素是引用类型,该方法变为get((Object arr, int index)
- static void setXxx((Object arr, int index, xxx val):向arr数组的第index位置插入val值
对于上述方法,下面有个非常简单的例子:
public class ReflectArrayTest {
public static void main(String args[]) {
try {
// 创建长度为5,元素类型为String的数组
Object arr = Array.newInstance(String.class, 5);
Array.set(arr, 3, "ttt");
Array.set(arr, 4, "fff");
Object obj = Array.get(arr, 3);
Object obj1 = Array.get(arr, 4);
} catch (Throwable e) {
System.err.println(e);
}
}
}
上述例子只是创建了简单的一维数组,利用Array.newInstance还可以创建多维数组。
2、newInstance()方法返回值并不是泛型
在上述例子虽然创建String数组,但是其返回值只是简单的Object对象,如果需要将arr对象当成String[]数组来用,就必须使用强转:String[] cast = (String []) arr;,但是强转是不安全的操作。而在反射中使用泛型Class<T>,可以有效避免强制类型转化。
观察Array的newInstance的方法签名,可以观察到奇怪的一点:
public static Object newInstance(Class<?> componentType, int... dimensions)
虽然方法签名中使用了Class<?>泛型,但实际上并没有真正利用泛型。如果将方法返回值改成如下形式:
public static <T> T[] newInstance(Class<T> componentType, int... dimensions) 这样就可以在调用该方法后无需强制类型转化了。不过改动了的这个方法只能暂时创建一维数组,就不能利用可变个数的参数优势了。
我们可以将Array的newInstance方法封装一下:
public class PackageArray {
// 强转的时候,会有一个unchecked编译警告,使用该注解可以抑制这个警告信息
@SuppressWarnings("unchecked")
public static <T> T[] newInstance(Class<T> componentType, int length) {
return (T[])Array.newInstance(componentType, length);
}
}
封装后,调用PackageArray的newInstance类方法,就可直接获取到具体元素类型的数组对象了。