Collection.toArray() java.lang.ClassCastException - java

import java.util.HashMap;
import java.util.Map;
public class Main
{
public static void main(String[] args)
{
Map<Integer,Class> map=new HashMap<Integer,Class>();
map.put(0,Main.class);
Class[] classes=(Class[])map.values().toArray();
for (Class c:classes)
System.out.println(c.getName());
}
}
I try cast in this line Class[] classes=(Class[])map.values().toArray(); but get exception.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Class;
at Main.main(Main.java:11)
What is problem?

Change:
Class[] classes = (Class[]) map.values().toArray();
To:
Class[] classes = map.values().toArray(new Class[0]);
This gives information on which type of array to convert the Collection to. Otherwise, it returns an array of type Object (and that cannot be cast to an Class[]).
Quoted from the API documentation for Collection.toArray(T[] a):
Returns an array containing all of the elements in this collection; the runtime type of the returned array is that of the specified array. ...
Note that toArray(new Object[0]) is identical in function to toArray().

toArray() returns an Object[] [and not any object derived from Object[]]. Each element in this array is of type Class, but the array itself is not of type Class[]
You should cast each element in the array to Class instead of trying to cast the array, or use Collection.toArray(T[]) to avoid casting.

Use T[] toArray(T[] a) from Collection instead.

Use this code for listing out the values of map i.e. class names:
Object[] array = map.values().toArray();
for (Object object : array) {
System.out.println(object.toString());
}

Related

Java type erasure and Arrays

The oracle doc says Generics are implemented in java using a technique call type erasure and this is how it works.
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
So if I have a Generic class say Container as below:
class Container<T>{
T initialValue;
List<T> valueList=new ArrayList<T>();
public List<T> getValueList(){
return valueList;
}
}
it's equivalent class would look like after being processed by type erasure:
class Container{
Object initialValue;
List valueList=new ArrayList();
public List getValueList(){
return valueList;
}
}
Correct me if a wrong here
Similarly, if a modify the above class as below
class Container<T>{
T initialValue;
List<T> valueList=new ArrayList<T>();
T[] arrayValue;
public Container(T[] array){
arrayValue=array;
}
public List<T> getValueList(){
return valueList;
}
}
won't be this equivalent to???
class Container{
Object initialValue;
List valueList=new ArrayList();
Object[] arrayValue;
public Container(Object[] array){
arrayValue=array;
}
public List getValueList(){
return valueList;
}
}
if this is true then I should also have like this:
T[] arrayValue=new T[10];//Compile time error;
as the above statement would get converted into
Object[] arrayValue=new Object[10];
Need clarity on how type erasure works for Arrays in Java??
You cannot create generic arrays. The reason is that arrays predate Java's generics, and arrays do not use type erasure. So, for example, an Integer[] and a String[] really have different type at runtime. If you write new T[], the compiler doesn't know what kind of array it needs to create.
You can create a fake generic array by doing:
T[] array = (T[]) new Object[10];
But you have to remember that you really created an Object array, not a T array. At run-time it is possible to put non-T instances in it, so only do this if the array is a private field of your class which is never passed to other objects, so that you can control exactly what objects are put in the array.
If you have a Class<T> instance (a so-called type token) you can use Array.newInstance to create a new array with the correct run-time type:
T[] array = (T[]) Array.newInstance(typeToken, 10);

Java initializing a generic array

T[] genericArray= (T[])(new Object[2]);
T has a constraint that it implements Comparable. The line above fails with an exception
" java.lang.ClassCastException: [Ljava.lang.Object;
cannot be cast to [Ljava.lang.Comparable;
How do I initialize a generic array where the T has constraints?
Object doesn't implements Comparable.
Instead of creating it as Object[] create it as Comparable[].
Related to your comment:
A variable can be declared of any type. When you create an array you are not creating objects inside the array, but you are only allocating the memory to store the references to the objects.
So as you can write:
Comparable x = "Pippo"; // Because String is Comparable
you can also write
Comparable[] x = new Comparable[1];
x[0] = "Pippo"; // Here you add a concrete String that is a
// Comparable type on the first position
You get this error because Object does not implement Comparable and thus Object[] is not a sub-type of Comparable[] (which, because of type erasure, is the runtime type of your genericArray).
The underlying problem is that you want to create a generic array. This is not possible in Java. The reason is, that unlike generics, the type of the elements of an array is known at runtime. If you write new T[], it is not known which type of array must be created.
You try to circumvent this by creating an array of some supertype. But this is also not correct (and you should get a warning if you do it). If you create a an array with new Comparable[size], you create a an array of Comparables, not an array of some subtype of Comparable. A T[] might be a String[] or a Long[], and String[] and Long[] are different types than Comparable[] (also at runtime).
To demonstrate the problem, consider the following program:
public class Foo<T extends Comparable> {
T[] createArray() {
return (T[])new Comparable[1];
}
public static void main(String... args) {
Foo<String> foo = new Foo<>();
String[] ss = foo.createArray(); // here
}
}
It might look perfectly okay at first sight, but when your run it, you get a ClassCastException, because in the marked line a Object[] is cast to a String[].
The solution is to use Class<T> objects as so-called type tokens. These let you store the type so that you can access it at run-time. Now you can create an array with the correct type by using Array.newInstance(Class<T>, int...). For example:
public class Foo<T extends Comparable> {
private Class<T> type;
public Foo(Class<T> type) {
this.type = type;
}
T[] createArray() {
return (T[])Array.newInstance(type, 1);
}
public static void main(String... args) {
Foo<String> foo = new Foo<>(String.class);
String[] ss = foo.createArray();
}
}
(You may still get a warning from the compiler, because newInstance's return type is Object. You can ignore it because the object it returns is an array of the correct type.)

In which condition which overloaded version of toArray() and toArray(T[] a) should be use?

I never use overloaded version of toArray Object[] toArray(Object[] a) to convert collection into array.
below is my javacode-
public class Track {
public static void main(String x[]) {
ArrayList<String> iName = new ArrayList<String>();
iName.add("Arpit1");
iName.add("Arpit2");
iName.add("Dubey1");
iName.add("Dubey2");
Object[] array= iName.toArray();
for(int i=0;i<array.length;i++)
System.out.println(array[i].getClass());
}
}
Output-
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String
Expected-
class java.lang.Object
there are some other question related this I go through all but no one pointing my query.
You need to use the overloaded method to get an array of the appropriate type. Otherwise the returned array will always be of type Object[].
Your code - which uses the toArray() method without parameters - returns an object array which cannot be cast to an array of another type and thus will throw an exception:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
Before going any further, whatever may be the result of your toArray method, the elements of the array will always remain of type String.
for(int i=0;i<array.length;i++)
System.out.println(array[i].getClass());
Thus, this will always return class java.lang.String.
You may expect that the elements will be converted to Object if you store them in an Object[], but that's not the case. The array is just the container.
That being said, the paramater of the toArray indicates the type of the array to be constructed. So, you could store a list of Integers in a Number[] array.

The type parameter T is hiding the type T in <T> T[] toArray(T[] a) using Eclipse

Using eclipse 4.2 with Java 7 and trying to implement the following method of the List interface i got a warning.
public <T> T[] toArray(T[] a) {
return a;
}
The warning says :
The type parameter T is hiding the type T
Why ? How can i get rid of it ?
The List interface is also generic. Make sure that you are not also using T for the generic type in your class. Note that in http://docs.oracle.com/javase/6/docs/api/java/util/List.html, they use "E" for the class generic parameter and "T" for the toArray() generic parameter. This prevents the overlap.
public class MyList<T> implements List<T> {
// V1 (compiler warning)
public <T> T[] toArray(T[] array) {
// in this method T refers to the generic parameter of the generic method
// rather than to the generic parameter of the class. Thus we get a warning.
T variable = null; // refers to the element type of the array, which may not be the element type of MyList
}
// V2 (no warning)
public <T2> T2[] toArray(T2[] array) {
T variable = null; // refers to the element type of MyList
T2 variable2 = null; // refers to the element type of the array
}
}
Another option is that you have an import of a class called "T" and that's why you are getting the warning. I have just solved my problem after finding out that i had an useless import to:
org.apache.poi.ss.formula.functions.T
tl;dr: Check your imports!

Casting from type object to a class

I'm currently trying to populate an array of of objects of the type Stipulations which is a class which is an
public abstract interface
My method of populating this array is as follows where popStipAttr is a simple switch statement.
public static Stipulations[] popStipArr(ZASAllocation zasAlloc)
{
//ArrayList<String> s = new ArrayList<String>();
ArrayList<Stipulations> stipAL = new ArrayList<Stipulations>();
for(int i = 0; i < NoStip; i++)
{
stipAL.add(popStipAttr(i,zasAlloc));
}
Stipulations[] StipArr = (Stipulations[]) stipAL.toArray();
return StipArr;
}
However I get the error about casting:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lc.Stipulations;
What exactly am I doing wrong here I created the arraylist of the same type, why would coverting it to an array of that type throw this?
ArrayList.toArray returns an Object[] (which, as stated in the message, can't be cast to Stipulations[]). ArrayList.toArray(T[] a) however, returns a T[]. Thus, change
Stipulations[] StipArr = (Stipulations[]) stipAL.toArray();
to
Stipulations[] StipArr = (Stipulations[]) stipAL.toArray(new Stipulations[0]);
^^^^^^^^^^^^^^^^^^^
Oh, right. Just realized what may have caused the confusion. The leading [ in [Ljava.lang.Object; indicates that it is an array. Same for [Lc.Stipulations;. Perhaps that's why you wrote Casting from type object to a class as title :-) Now you know anyway :-)
What you are doing in
Stipulations[] StipArr = (Stipulations[]) stipAL.toArray();
is calling the method on the java.util.List class
Object[] toArray();
which is returning you an Object[] which cant be cast to your Stipulations[]
What you want to be calling is the method on java.util.List
<T> T[] toArray(T[] a);
which will return you the array with your type.
So try
Stipulations[] StipArr = stipAL.toArray(new Stipulations[stipAL.size()]);
It is a strange syntax which tends to pollute the code and for this reason and a few others I always try to use Lists where possible and never convert to and from Arrays unless absolutely necessary like an external API not under my control requires it

Categories