【问题标题】:Create Static Array from dynamic array with Generics [duplicate]使用泛型从动态数组创建静态数组[重复]
【发布时间】:2020-05-24 19:40:00
【问题描述】:

我想从动态数组的任何泛型类型的动态数组创建一个静态数组。我看到返回 Object[] 的 List#toArray() 并且它不使用泛型。将其强制转换为 T[] 是否安全,还是必须从使用它的类类型实例化整个数组?

我继续尝试创建自己的方法,以防 java 没有提供,但是我遇到了编译错误

public static <T> T[] toArray(List<T> list)
{
    T[] li = (T[]) Array.newInstance(T.class, list.size());
    int index = 0;
    for(T obj : list)
    {
        li[index++] = obj;
    }
    return li;
}

【问题讨论】:

  • 尽量避免混合使用数组和泛型。数组是协变的和保留的,而泛型是不变的和擦除的。这是麻烦的秘诀。 Even ArrayList uses an Object[] as its backing structure 并且仅在返回元素时进行强制转换。 --- 由于泛型的擦除特性,它们的类型信息仅在编译时可用,这就是您无法在运行时访问T.class 的原因。
  • 还要注意,上面使用newInstance()的代码并不比toArray()好——两者都需要转换
  • 如果可以做到这一点,您不认为它会包含在集合 API 中吗?

标签: java arrays arraylist dynamic static


【解决方案1】:

首先,你不需要那个方法。您可以使用:

List<String> list = new ArrayList<>();
list.add("ff");
list.add("bb");
String[] array = list.toArray (new String[list.size ()]);

为了让你的方法工作,你必须传递泛型类型参数的Class

public static <T> T[] toArray(List<T> list, Class<T> clazz)
{
    T[] li = (T[]) Array.newInstance(clazz, list.size());
    int index = 0;
    for(T obj : list)
    {
        li[index++] = obj;
    }
    return li;
}

然后你可以调用该方法:

String[] array = toArray(list, String.class);

【讨论】:

  • 使用 ArrayList#toArray() 转换为 T[] 是否安全?它会接受不是它的强制类型的其他对象吗?
  • @nullsector76 没有。你会得到一个 ClassCastException,因为 ArrayList#toArray() 返回一个 Object[],它不能转换为 T[]。 (除非 T 也是 Object)
【解决方案2】:

如果你有一个泛型元素类型,Eran 提出的方法就行不通,因为你不能得到一个Class&lt;List&lt;T&gt;&gt;,比如说。

改为传递IntFunction&lt;T[]&gt;

public static <T> T[] toArray(List<? extends T> list, IntFunction<T[]> arraySupplier)
{
    T[] li = arraySupplier.get(list.size());
    int index = 0;
    for(T obj : list)
    {
        li[index++] = obj;
    }
    return li;
}

或者,更简单,使用流:

return list.stream().toArray(arraySupplier);

然后像这样调用:

String[] array = toArray(list, String[]::new);

List<List<String>> listOfLists = ...
List<?>[] arrayOfLists = toArray(listOfLists, List<?>::new);

请注意,虽然这确实支持通用数组元素,但您只能创建具有具体元素类型的数组,因此您的数组类型必须是 List&lt;?&gt;[];仍然不能是List&lt;String&gt;[]

【讨论】:

    【解决方案3】:

    如果您的业务需求/用例要求数组不再是动态的,那么您应该首先创建一个大小等于您的动态数组大小的静态数组。

       ArrayList<Integer> al = [............] // assuming that ArrayList named al is having some data
       int[] arr = new int[al.size()];
    
       // from here you can use a for loop and initialize your static array
       for(int i=0; i<arr.length;i++) {
           arr[i] = (int) al.get(i); // Unboxing will also be done but still you can type cast to be on safe side
       }
       // Now you can de-reference the ArrayList object and call garbage collection which will wipe it out of the Heap Memory of your JVM.
       al = null; // de-referencing the object by making the reference variable null
       System.gc(); // GC happens periodically but to boost performance you can explicitly call it right away.
    

    您可以创建一个接受对象列表的方法,并且可以使用instanceof 运算符处理各种数组。

    【讨论】:

    • 但是new 不适用于泛型类型T(问题的主要点——如果我在编译时知道类型,那么在运行时创建一个数组是没有问题的)
    猜你喜欢
    • 2018-07-23
    • 1970-01-01
    • 2013-09-06
    • 2018-12-16
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    相关资源
    最近更新 更多