简体   繁体   English

返回Java中通用类型的数组

[英]Returning an Array of a Generic Type in Java

I have a class mapper that is supposed to apply any object that implements the Function interface to an array of type D, and return an array of type R. 我有一个类映射器,该类映射器应该将实现Function接口的任何对象应用于D型数组,并返回R型数组。

The problem is that Java does not let me use "new R[]," and so far I've struggled to figure out a way to create an R array from scratch. 问题是Java不允许我使用“ new R []”,到目前为止,我一直在努力寻找一种从头开始创建R数组的方法。 I currently am attempting to use the Array.newInstance method, but can't find a way to store the class type of R in a Class variable. 我目前正在尝试使用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()); 

}

}

What can I do properly attain a class value at runtime for the generic type R, or otherwise return the objects in ArrayList as an R[]? 我如何在运行时正确地获得泛型R的类值,或者将ArrayList中的对象作为R []返回?

The problem you are facing is related to Java generics type erasure. 您面临的问题与Java泛型类型擦除有关。 Since all generic types are erased at runtime, Java has to make trade offs to guarantee type safety. 由于在运行时会擦除所有通用类型,因此Java必须做出权衡以保证类型安全。

The problem with generic arrays is that Java would not be able to guarantee that type safety, you can find a good example about this here . 通用数组的问题在于Java无法保证类型安全,您可以在此处找到一个很好的例子。 In short, generic array creation is not allowed. 简而言之,不允许创建通用数组。

To keep most of your original code, you can use Object[] : 要保留大多数原始代码,可以使用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!
}

But, that´s why most people stick to lists, as it is way easier to operate with them when generics are involved: 但是,这就是大多数人坚持使用列表的原因,因为在涉及泛型时使用它们更容易进行操作:

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;
}

And the good part about this is that you can still convert it to an array afterwards when the concrete type is known: 与此相关的好处是,当具体类型已知后,您仍然可以将其转换为数组:

List<String> strings = List.of("Test1", "Test2");
String[] array = map(String::toLowerCase, strings).toArray(new String[0]);

The cleanest way to do this is to simply pass a Class object to the function. 最简单的方法是将Class对象传递给函数。 Also, it seems like you have the order of the type parameters to Function reversed -- the first type parameter should be the input type and the second should be the result type. 另外,似乎您已经将类型参数的顺序改为“ Function反转”了-第一个类型参数应该是输入类型,第二个应该是结果类型。 Something like this should get you closer to what you want: 这样的事情应该使您更接近所需的内容:

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;
}

(I'd also suggest reversing the order of the type parameters to your method, to be consistent with the built-in reflection classes like Function .) (我还建议将类型参数的顺序反转为您的方法,以与诸如Function类的内置反射类保持一致。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM