Java使用反射的通用数组复制方法

时间:2023-01-19 19:10:33

Java通用数组复制方法

在Arrays工具类中,提供了一个copyOf(T[] original, int newLength)方法,用于复制任意类型的对象数组,但是由于泛型不能作用于基本类型,所以Arrays工具类中又额外提供了处理基本数据类型数组的函数,但是使用反射可以讲这些方法都统一起来。

为了对比,先来看一个实现的不太好的数组拷贝的例子:

public static Object[] badCopy(Object[] objects, int newLength) {
Object[] des = new Object[newLength];
System.arraycopy(objects, 0, des, 0, Math.min(newLength, objects.length));
return des;
}

这个方法copy方法在很多情况下也能正常工作,但是存在很多问题。

首先,只能拷贝对象数组。因为传递的参数是Object[],所以难以扩展到基本类型;

其次,由于使用Object[]声明新数组,所以没法将返回结果转换为想要拷贝的实际类型。比如想拷贝的是Person对象的数组,但是这里的返回值是一个Object的数组,而且还无法转换成。在Java中,如果一开始声明的是Object对象,将它临时转换到Object,然后再转回来是可以的,但是如果一开始就声明了Object,就无法向下转型了,Java会记住声明时的类型信息,也就是一个对象的静态类型信息。

为了解决以上问题,使用如下的方法:

public static Object copyOf(Object arr, int newLength) {
Class cl = arr.getClass();
// 如果不是数组 返回
if (!cl.isArray()) return null;
// 获取数组中元素的类型
Class componentType = cl.getComponentType();
// 创建新数组实例
Object res = Array.newInstance(componentType, newLength);
System.arraycopy(arr, 0, res, 0, Math.min(newLength, Array.getLength(arr)));
return res;
}

该方法接受Object对象作为参数,所以可以处理基本类型,因为数组总是一个对象,对象类型的数组是一个数组对象,基本类型的数组同样是数组对象,所以可以正确的传递参数;

再看内部实现中,获取数组的类对象,然后再使用获取数组中元素的类型,用这个类型来创建新的数组,这就保证了最终可以将结果向下转型为想要的类型;返回的类型是Object,通过上述描述可知,得到结果后,只要手动的转换成想要的类型即可。

public static void main(String[] args) {
int[] a = new int[]{1, 2, 3, 4};
int[] b = (int[]) CopyArray.copyOf(a, 3);
System.out.println(Arrays.toString(b)); String[] c = new String[]{"xx", "yy", "zz"};
String[] d = (String[]) CopyArray.copyOf(c, 10);
System.out.println(Arrays.toString(d));
}

这个方法虽然可以将所有类型数组的拷贝统一,但是不好的地方在于需要手动进行类型转换,而Arrays工具类中,虽然没有统一所有方法,但是使用重载将让用户可以更方便的使用,而不需要类型转换。

或许这就是通用和专用的权衡吧。