我有一个类映射器,它应该将实现 Function 接口的任何对象应用于 D 类型的数组,并返回 R 类型的数组。
问题是 Java 不允许我使用“new R[]”,到目前为止我一直在努力寻找一种从头开始创建 R 数组的方法。我目前正在尝试使用 Array.newInstance 方法,但找不到将 R 的类类型存储在 Class 变量中的方法。
public class Mapper {
/**
* applies passed function to each object of type D in array
* @param function
* @param array
* @return array of type r and length array.length
*/
public static <R, D> R[] map(Function<R, D> function, D[] array) {
ArrayList<R> list = new ArrayList<R>();
//apply function to each variable
//add rs into object array
for( int i = 0; i < array.length; i++ ) {
R r = function.apply( array[i] );
list.add( r );
}
Class<R> clazz = list.get(0).getClass();
return (R[])Array.newInstance(clazz, list.size());
}
}
如何在运行时正确获取泛型类型 R 的类值,或者以 R[] 的形式返回 ArrayList 中的对象?
您面临的问题与Java泛型类型擦除有关。由于所有泛型类型都会在运行时被擦除,因此 Java 必须做出权衡以保证类型安全。
泛型数组的问题是 Java 无法保证类型安全,您可以在here找到一个很好的例子。简而言之,不允许创建通用数组。
要保留大部分原始代码,您可以使用
Object[]
:
public static <D, R> Object[] map(Function<D, R> function, D[] array) {
List<R> list = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
R r = function.apply(array[i]);
list.add(r);
}
return list.toArray(new Object[0]); // no generic array creation allowed!
}
但是,这就是为什么大多数人坚持使用列表的原因,因为当涉及泛型时使用它们会更容易:
public static <D, R> List<R> map(Function<D, R> function, List<D> array) {
List<R> list = new ArrayList<>();
for (D d : array) {
list.add(function.apply(d));
}
return list;
}
这样做的好处是,当具体类型已知时,您仍然可以将其转换为数组:
List<String> strings = List.of("Test1", "Test2");
String[] array = map(String::toLowerCase, strings).toArray(new String[0]);
最简洁的方法是简单地将
Class
对象传递给函数。另外,似乎类型参数的顺序 Function
颠倒了——第一个类型参数应该是输入类型,第二个类型参数应该是结果类型。像这样的事情应该会让你更接近你想要的:
public static <R, D> R[] map(Function<D, R> function, D[] array, Class<R> clazz) {
R[] result = (R[]) Array.newInstance(clazz, array.length);
// apply function to each variable and add return value to the result array
for( int i = 0; i < array.length; i++ ) {
result[i] = function.apply(array[i]);
}
return result;
}
(我还建议反转方法中类型参数的顺序,以与
Function
等内置反射类保持一致。)
我用的是这个方法:
示例:
Customer[] customers=createNew(100);
@NonNull
public static <T> T[] createNew(int capacity, @NonNull T... array) {
return java.util.Arrays.copyOf(array, capacity);
}