当前位置: 首页 > 面试题库 >

如何转换清单 使用通用方法将数组t [](对于基本类型)设置为?

章城
2023-03-14
问题内容

我正在使用泛型方法进行一些测试,我想仅用一个(convertListToArray)转换以下两种方法(convertFloatListToArray和convertShortListToArray):

public class Helper{
    public static float[] convertFloatListToArray(List<Float> list){
        float[] array = new float[list.size()];

        for(int i = 0; i<list.size(); i++){
            array[i] = list.get(i);
        }

        return array;
    }

    public static short[] convertShortListToArray(List<Short> list){
        short[] array = new short[list.size()];

        for(int i = 0; i<list.size(); i++){
            array[i] = list.get(i);
        }

        return array;
    }
}

但是当我尝试使用泛型时,如下所示,我有一些错误:

public class Helper{
    public static <T, E> T convertListToArray(List<E> list){
        T array = new T[list.size()];

        for(int i = 0; i<list.size(); i++){
            array[i] = list.get(i);
        }

        return array;
    }
}

我可以理解Java关于泛型的局限性,但是我想知道是否有人知道我没有看到任何使用泛型方法的解决方案。


问题答案:

从当前版本(Java
12)开始,基本类型无法用Java泛型表示。更具体地说,我们不能提供原始类型作为类型参数。(例如,我们不能这样做Foo<int>。)我们也不能将类型变量用作new表达式中的类型,因此不能new T[n]创建数组。因此,没有理想的方法来执行此操作。


可能做到这一点合理的使用一些反射(java.lang.reflect.Array),但我们需要提供一个Class作为参数。这是一个可能如何完成的示例:

/**
 * Unboxes a List in to a primitive array.
 *
 * @param  list      the List to convert to a primitive array
 * @param  arrayType the primitive array type to convert to
 * @param  <P>       the primitive array type to convert to
 * @return an array of P with the elements of the specified List
 * @throws NullPointerException
 *         if either of the arguments are null, or if any of the elements
 *         of the List are null
 * @throws IllegalArgumentException
 *         if the specified Class does not represent an array type, if
 *         the component type of the specified Class is not a primitive
 *         type, or if the elements of the specified List can not be
 *         stored in an array of type P
 */
public static <P> P toPrimitiveArray(List<?> list, Class<P> arrayType) {
    if (!arrayType.isArray()) {
        throw new IllegalArgumentException(arrayType.toString());
    }
    Class<?> primitiveType = arrayType.getComponentType();
    if (!primitiveType.isPrimitive()) {
        throw new IllegalArgumentException(primitiveType.toString());
    }

    P array = arrayType.cast(Array.newInstance(primitiveType, list.size()));

    for (int i = 0; i < list.size(); i++) {
        Array.set(array, i, list.get(i));
    }

    return array;
}

示例调用:

List<Integer> list = List.of(1, 2, 3);
int[] ints = toPrimitiveArray(list, int[].class);

请注意,这Array.html" target="_blank">set将执行扩展的原始转换,因此可以进行以下工作:

List<Integer> list = List.of(1, 2, 3);
double[] doubles = toPrimitiveArray(list, double[].class);

但是它不会执行缩小的转换,因此以下内容引发异常:

List<Integer> list = List.of(1, 2, 3);
byte[] bytes = toPrimitiveArray(list, byte[].class); // throws

如果您愿意,该代码还可用于简化复制:

public static int[] toIntArray(List<Integer> list) {
    return toPrimitiveArray(list, int[].class);
}
public static double[] toDoubleArray(List<Double> list) {
    return toPrimitiveArray(list, double[].class);
}
...

(不过,具有多个类似方法并不是真正的 通用 。)

您有时会看到地点的一种解决方案如下所示:

public static <P> P toPrimitiveArray(List<?> list) {
    Object obj0 = list.get(0);
    Class<?> type;
    // "unbox" the Class of obj0
    if (obj0 instanceof Integer)
        type = int.class;
    else if (obj0 instanceof Double)
        type = double.class;
    else if (...)
        type = ...;
    else
        throw new IllegalArgumentException();

    Object array = Array.newInstance(type, list.size());

    for (int i = 0; i < list.size(); i++) {
        Array.set(array, i, list.get(i));
    }

    return (P) array;
}

但是,有很多问题:

  • 如果列表为空,我们不知道要创建哪种类型的数组。
  • 如果列表中的对象类型不止一种,则无法使用。
  • 未经检查的将结果数组强制转换为P,因此存在堆污染的危险。

最好只传入a Class作为参数。

另外,虽然可以编写许多重载来取消数组装箱:

public static int[]    unbox(Integer[] arr) {...}
public static long[]   unbox(Long[]    arr) {...}
public static double[] unbox(Double[]  arr) {...}
...

由于类型擦除的影响,不可能编写将许多不同类型的拆箱的重载,List如下所示:

public static int[]    unbox(List<Integer> list) {...}
public static long[]   unbox(List<Long>    list) {...}
public static double[] unbox(List<Double>  list) {...}
...

那不会编译,因为在同一个类中,我们不允许有多个具有相同名称和擦除的方法。这些方法必须具有不同的名称。

附带说明一下,这是一些非通用解决方案:

  • 从Java 8中,我们可以拆箱ListIntegerLongDouble使用StreamAPI:

    List<Long> list = List.of(1L, 2L, 3L);
    

    long[] longs = list.stream().mapToLong(Long::longValue).toArray();

  • Google Guava has Collection unboxing methods in their com.google.common.primitives classes, for example Doubles.toArray:

    List<Double> list = List.of(1.0, 2.0, 3.0);
    

    double[] doubles = Doubles.toArray(list);



 类似资料:
  • 当然,这段代码不起作用。因为get()和set()方法。我可以用那样的东西吗?

  • 问题内容: 从他的问题中很明显,他需要从任何数据类型转换为另一种类型。当我说“数据类型”在这里,我的意思是类型仅限于那些常用来代表原始数据:,,等。对于这个问题,我们可以考虑原语装箱的目的。 我想知道是否有任何API支持类型之间的转换,其中输入和输出都被概括为一组受支持的数据类型。我看了Apache Commons的beanutils.converters包 ,但是每个已知输入都有一个单独的转换器

  • 我的一个数据帧(spark.sql)有这个模式。 我需要将其保存到CSV文件,但不使用任何扁平化,以以下格式分解。 我直接使用了命令 ,这符合我的目的,但我需要一个更好的方法。我正在使用派斯帕克

  • 问题内容: 我有这个: 输出: 为什么我在这里出错? 和 错误的含义是什么? 它告诉我什么? 问题答案: 您在这里遇到错误,是因为当您使用接受varargs的函数时,此函数在幕后创建了您在其中传递的对象的新数组。因此,实际上得到 了一个整数数组 。 当您传递整数 数组时,请 在后台创建 一个 整数 数组数组 。这就是为什么您不能通过以下循环对其进行迭代: 尝试像这样更改它: 实际上,您将看到对传递

  • 问题内容: 在Java中,从Object转换为其他类型时,为什么第二行会产生与转换相关的警告,而第一行却没有? 问题答案: 这是因为在执行时,由于 类型Erase 不会 真正 检查对象是否为a 。真的只是将其投射到。例如: __ 有关更多信息,请参见Angelika Langer的Java泛型常见问题解答 ,尤其是类型擦除部分。

  • 问题内容: 我做了以下数组: 我想知道如何使用stdClass()将此数组转换为对象,我是PHP初学者,一个简单的示例会非常有帮助,我尝试搜索类似的问题,但是答案很复杂,而且超出了我对基本类和对象的理解。 问题答案: 您只需添加此代码 如果要查看此stdClass对象,只需调用此 如果要将数组转换为目标代码,将 您不需要使用stdClass。它将自动转换为stdClass