5.7 反射
5.7.6 用反射设计通用数组的代码
java.lang.reflect包中的Array类允许我们动态的创建数组,我们尝试用这个特性自己实现一下Arrays(java.util.Arrays)的copyOf方法。
第一版的代码为
public static Object[] badCopyOf(Object[] a, int newLength) // not useful
{
var newArray = new Object[newLength];
System.arraycopy(a, 0, newArray, 0, Math.min(a.length, newLength));
return newArray;
}
这个代码是存在问题的,这个方法返回的Object[](Object数组对象)没法转换为我们需要的对象,例如之前的Employee。这是因为Java的数组对象会记录它的入口类型,即我们使用new创建这个数组时使用的类型,这就导致了最初以Employee[]创建的数组能转换为Object[],并且再这之后还能再一次的转换为Employee[]。但是以Object[]创建的数组不能转换为Employee。
我们可以使用Array的一个静态方法newInstance构造数组来解决这个问题。
于是有了第二版的代码:
public static Object goodCopyOf(Object a, int newLength) {
Class cl = a.getClass();
if (!cl.isArray()) return null;
Class componentType = cl.getComponentType();
int length = Array.getLength(a);
Object newArray = Array.newInstance(componentType, newLength);
System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
return newArray;
}
你可能已经注意到了方法参数也有一些变化,即原本的Object[] a变为了Object a这是因为我们的方法需要兼容Java的基本数据类型(int, double, long ...),这个基本数据类型的数组是可以转换为Object对象的,但是没办法转换为一个Object对象的数组(Object[])。
也许你会对这份代码产生一点违和感(恭喜,对感受代码的直觉能力蛮高),getComponent方法是属于Class的,而getLength方法是属于Array的。至于为什么是这样,我也不知道了……