Here we have generic method:
public static <T extends Comparable<T>> T[] function(T[] a)
{
Object[] m = new Object[2];
/* some work here */
return (T[]) m;
}
A ClassCastException
is thrown . What's wrong with it?
Here we have generic method:
public static <T extends Comparable<T>> T[] function(T[] a)
{
Object[] m = new Object[2];
/* some work here */
return (T[]) m;
}
A ClassCastException
is thrown . What's wrong with it?
An array of Object is not an array of any subclass of Object. You are facing one of the limitations of generics in Java: you cannot create a generic array. See this thread for an approach that does work.
Object
is not Comparable
. You have to define your array to be of a comparable type.
Since you are passing an array, you can perhaps use the array's type:
T[] m = Array.newInstance(a.getClass().getComponentType(), 2);
And of course, you will have to put Comparable
objects inside.
You have two different problems here.
First, just erase the generics and look at the code without generics (this is what it gets erased to at compile-time):
public static Comparable[] function(Comparable[] a)
{
Object[] m = new Object[2];
/* some work here */
return (Comparable[]) m;
}
You can't cast an object whose actual, runtime class Object[]
to Comparable[]
. Period.
Second, even if you re-wrote your code to create a Comparable[]
instead of Object[]
public static <T extends Comparable<T>> T[] function(T[] a)
{
Comparable[] m = new Comparable[2];
/* some work here */
return (T[]) m;
}
it would still not work. It won't throw a ClassCastException inside this function. But it will throw it in any code that calls this function. For example,
String[] foo = function(new String[0]);
will throw a ClassCastException, because when you erase it, you see that the compiler places a cast for the thing that comes out of the generic method:
String[] foo = (String[])function(new String[0]);
and you can't cast an object whose actual class is Comparable[]
to String[]
.
When you ask "what is the difference" to people who have said that Array.newInstance()
is the way to create an array of a class known at runtime. The difference is that the object returned by Array.newInstance()
has an ''actual, runtime'' type of Whatever[]
, where "Whatever" is the class of the class object passed to it. It doesn't matter that the static (compile-time type of the value) type is Object[]
; it's the actual runtime type that matters.
When you say "Another question is why E[] e = (E[]) new Object[3] works", you are probably missing several points here. First of all, that only works if E is declared as <E>
or <E extends Object>
, i.e. E's lower bound is Object. And second, that is basically a lie (that's convenient in several places, like implementing a generic collection; but you have to understand why it's dangerous); and formally, you ''shouldn't'' be able to cast from an object whose actual type is Object[]
to E[]
when E is not Object. It only "works" because within the scope of E, E is erased, and so we can't check the cast. But if you try to return that object as an E[]
to the outside world, you will get a ClassCastException in the same way.
Well, really you cannot cast an array of objects to an array of Comparables. It doesn't make any sense. Why would the compiler allow that? What's more, for example, the Integer class implements Comparable, but you cannot cast a Comparable array to an Integer array.
T extends Comparable means that method parameter (in this case T) should extend from comparable. So when you try to do the following cast
(T[]) m;
You are trying to cast an Object[] to Comparable[] (or anything that extends Comparable).
This is what you want to be doing:
public static <T extends Comparable<T>> T[] function(final T[] a) {
final T[] m = (T[]) Array.newInstance(a.getClass().getComponentType(), 2);
/* some work here */
return m;
}