泛型类型函数的返回语句出错



我正在尝试制作一个泛型函数,将数组(int[],String[])传递到该函数中,并使用TreeSort返回其排序版本。我甚至还没有机会开始调试它,因为主类拒绝接受int[]数组作为参数

树排序

public T[] treeSort(T[] arr) {
  T[] result = (T[]) new Object[arr.length];
  for (int i = 0; i < arr.length; i++)
    if (arr[i] != null) 
      add(arr[i]);
  Iterator it = iterator();
  int count = 0;
  while (it.hasNext()) 
    result[count++] = (T) it.next();
  return (T[]) result;
}

BinarySearchTree<Integer> tree2 = new BinarySearchTree<>();
int[] unsortedNums = {6,3,7,4,1,2,9,8,5};
int[] sortedNums   = tree2.treeSort(unsortedNums);

错误

BinarySearchTree类型中的方法treeSort(Integer[])不适用于参数(int[])

因此,我尝试将unsortedNumssortedNumsint更改为Integer(为什么这很重要?),现在运行它会产生以下错误:

错误r 2

线程"main"java.lang.ClassCastException中的异常:[Ljava.lang.Object;无法强制转换为[Ljava.lang.Comparable;

在线

T[] result = (T[]) new Object[arr.length];

在Java的泛型方法中,不允许创建泛型类型的数组。您试图通过创建一个Object数组并将其强制转换为泛型类型来规避此规则,但编译器太聪明了,无法执行此操作。这个规则的原因是泛型类型很可能是Interface,所以运行时不知道要创建哪个类。

例如,如果您确实需要保持未排序数组的原样并返回一个副本(通常,排序是在适当的位置进行的,因此您只需编辑原始数组),您可以让用户传递泛型的类型(如sp00m的答案),也可以让用户提供目标数组作为参数,这样您就不需要自己创建数组。

IMO,这里的最佳实践是使您的排序到位,而不是返回数据的排序副本。

代替:

T[] result = (T[]) new Object[arr.length];

你必须使用:

T[] result = (T[]) Array.newInstance(clazz, arr.length);

其中clazz是嵌套元素的类型:

public T[] treeSort(T[] arr, Class<T> clazz) {...}

最后,在调用时,使用装箱原语:

Integer[] unsortedNums = { 6, 3, 7, 4, 1, 2, 9, 8, 5 };
Integer[] sortedNums = treeSort(unsortedNums, Integer.class);

在Java中,数组在运行时知道它们的组件类型(组件类型是实际运行时数组类型的一部分),因此您需要在运行时指定组件类型来创建该类型的数组。

@spoom的回答向您展示了如何在给定传递到函数中的类对象的情况下创建数组。然而,您实际上已经拥有了这些信息,而无需单独传递。参数arr的类型为T[],这意味着数组对象的实际运行时类型必须是T[]或其子类。我们可以从中提取组件类型,并使用它来创建新的数组:

T[] result = (T[]) Array.newInstance(arr.getClass().getComponentType(), arr.length);

例如,Arrays.copyOf()和相关函数就是这样工作的。

不能在泛型中使用基元类型(int)。尝试使用对象包装器,例如

Integer[] unsortedNums = {6,3,7,4,1,2,9,8,5}; Integer[] sortedNums = tree2.treeSort(unsortedNums);

在Java中组合泛型和数组是有问题的;查看文章限制泛型的详细信息。

至于解决这个问题,最简单的方法不是使用数组,而是使用List。例如:

public List<T> treeSort(List<T> list) {
    List<T> result = new ArrayList<T>(list.size());
    for (int i = 0; i < list.size(); i++)
        if (list.get(i) != null)
            result.add(list.get(i));
    Iterator<T> it = list.iterator();
    int count = 0;
    while (it.hasNext())
        result.set(count++, it.next());
    return result;
}

请注意,我还没有测试逻辑。

最新更新