简体   繁体   中英

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

I'm implementing a Quicksort class in Java. For sorting to work, the items that are to be sorted need to be comparable, for example by implementing the Comparable interface. However, implementing Comparable gives me problems when casting at runtime in a method that returns array slices:

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. 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> .

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 = 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 . You need the slice array to have the same element type as the arr array. 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. (Or clone it, if you aren't allowed to modify the input.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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