简体   繁体   English

泛型类型实现接口时,无法将 Object 数组强制转换为泛型类型数组

[英]Can't cast array of Object to array of generic type when generic type implements interface

I'm implementing a Quicksort class in Java.我正在用 Java 实现一个 Quicksort 类。 For sorting to work, the items that are to be sorted need to be comparable, for example by implementing the Comparable interface.为了使排序起作用,要排序的项目需要具有可比性,例如通过实现Comparable接口。 However, implementing Comparable gives me problems when casting at runtime in a method that returns array slices:但是,在运行时在返回数组切片的方法中进行转换时,实现Comparable会给我带来问题:

public class QuickSorter<T extends Comparable<T>> {

    ...

    private T[] sliceOfArray(T[] arr, int start, int end) {
        Object[] slice = new Object[end - start];

        for (int i = start; i < end; i++) {
            slice[i] = arr[i];
        }

        return (T[]) slice; // Throws exception at runtime.
    }
}

The exception is:例外是:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
    at com.sortingalgos.QuickSorter.sliceOfArray(QuickSorter.java:55)
    at com.sortingalgos.QuickSorter.sort(QuickSorter.java:11)
    at com.sortingalgos.MainApp.main(MainApp.java:11)

How can I get around this?我怎样才能解决这个问题?

The simple fix is to change this line简单的解决方法是改变这一行

    Object[] slice = new Object[end - start];

to

    Comparable[] slice = new Comparable[end - start];

The business of casting to T[] is a hack.转换为T[]的业务是一种黑客行为。 It doesn't actually change tbe type of the array.它实际上并没有改变数组的类型。 You don't want to be passing it around pretending that it really is correctly typed.您不想假装它确实输入正确而传递它。 It may be clearer to use Object[] (or Comparable[] ) or just plain old List<T> .使用Object[] (或Comparable[] )或简单的旧List<T>可能更清楚。

You can't even do the following:您甚至无法执行以下操作:

        Object[] a = new Object[] {1,3,4,5};
        Integer[] b = (Integer[])a;
        System.out.println(Arrays.toString(b));

This is because there is no guarantee that Object[] a doesn't really look like the following:这是因为不能保证Object[] a看起来不像下面这样:

      Object[] a = new Object[]{1,3,4,5.7}

Which clearly is not an array of Integer.这显然不是整数数组。 But you could do this.但是你可以这样做。

        Object[] a = new Integer[] {1,3,4,5};
        Integer[] b = (Integer[])a;
        System.out.println(Arrays.toString(b));


The problem is that an array of Object isn't an array of Comparable .问题是Object数组不是Comparable数组。 You need the slice array to have the same element type as the arr array.您需要slice数组与arr数组具有相同的元素类型。 You can achieve this by changing你可以通过改变来实现这一点

Object[] slice = new Object[end - start];

to

T[] slice = java.lang.reflect.Array.newInstance(arr.class.getComponentType(), end - start);

In other words, use reflection to determine at runtime the element type, and create slice arrays of the same type.换句话说,使用反射在运行时确定元素类型,并创建相同类型的切片数组。

Using reflection is likely to be less performant, however.然而,使用反射的性能可能较低。 For an in-place sort algorithm like QuickSort, you shouldn't need to create any new arrays at all, you could just use the input array.对于像 QuickSort 这样的就地排序算法,您根本不需要创建任何新数组,您可以只使用输入数组。 (Or clone it, if you aren't allowed to modify the input.) (或者克隆它,如果你不允许修改输入。)

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

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