Java: (String[])List.Toarray() Gives Classcastexception

java: (String[])List.toArray() gives ClassCastException

This is because when you use

 toArray() 

it returns an Object[], which can't be cast to a String[] (even tho the contents are Strings) This is because the toArray method only gets a

List 

and not

List<String>

as generics are a source code only thing, and not available at runtime and so it can't determine what type of array to create.

use

toArray(new String[v2.size()]);

which allocates the right kind of array (String[] and of the right size)

ArrayList toArray method class cast exception

The class cast exception happened just because toArray() returns Object[]. Surely Object[] cannot cast to String[].

Insteadly, you can use this:

String[] list = toArray(new String[names.size()]);

which returns the right cast(String[]).

In what case does casting ArrayList Type .toArray() to (Type[]) have the potential for a Class Cast Error

It always fails.

I'm sure you're wondering why. Let's try to explain:

Unlike generics, which are entirely a figment of the compiler's imagination, an array does know its 'component' type. You can ask it:

String[] strings = new String[10];
Object[] o = strings; // compiles. This is itself problematic, see later.
System.out.println(o.getClass().getComponentType()); // prints 'java.lang.String'
o[0] = Integer.valueOf(0); // hmmmmmmmm!!!!!
String str0 = strings[0]; // ... but... wait.. that's an Integer, not a String!

Tossing the above in a java file, it....

compiles??

Yes, it does. It shouldn't have, really - the reason it compiles, even today, is that java started out allowing the above, and java does not like breaking backwards compatibility. This code used to compile, so it still does. But this is obviously not right - I have put an integer in a string array. And that's why when you run it, this does not work: You get an ArrayStoreException on the line where you put an integer into o[0].

Let's try this with generics. The same thing, just, genericsed:

List<String> strings = new ArrayList<String>();
List<Object> o = strings; // the evil occurs here
// hmmm, List doesn't appear to have a getComponentType()....
o.add(Integer.valueOf(0));
String str0 = strings.get(0);

Now, sanity has been restored: That second line, where the evil occurs? The compiler doesn't let you do that. As it shouldn't, because then you run into the problems that these snippets show. In computer science-ese, array assignment is covariant, whereas with generics it is invariant. In the real world, this stuff is invariant (hence why the first snippet blows up), so generics got it right, arrays got it wrong, but we can't fix it - java should be backwards compatible.

Now that you know this, the problems with toArray() become clear:

  1. It is not possible for the toArray() method to know what component type the list is; therefore, if you have a List<String> and call toArray() on it, the toArray code cannot possibly obtain String from itself, unlike with arrays the component type is not stored. Generics are a figment of the compiler's imagination, it is nowhere in your class files, only in your source files. Thus, it doesn't know, so, it makes an array of objects (as in, the array that falls out of toArray() is technically an Object, calling its getComponentType will always print class java.lang.Object.

  2. It is legal to assign a String[] to Object[], because the java lang spec defines arrays to be covariant. But real life isn't like that. Also, the lang spec also says that the reverse does not hold: You cannot cast an instance of Object[] to type String[]. This is why it will always fail - the toArray() method ALWAYS produces an Object[], which cannot be cast like that.

  3. But let's say you could have hypothetically done that: If you then assign a non-string object to one of the array's slots, the ArrayStoreException does not happen, because the component type is incorrect.

  4. And now you get a classcastexception later on when you read it back in.

Let's try it:

List<String> list = new ArrayList<String>();
list.add("Hello!");
String[] strings = (String[]) list.toArray(); // this fails...
Object[] o = strings;
o[0] = Integer.valueOf(5);
String str0 = strings[0]; // but otherwise you'd be in trouble here.

The solution

The fix is trivial:

NB: In java, we write 'operatorIndex', not 'operator_index'. When in rome, be like romans.

return operators.get(operatorIndex).operation(thisArgs.toArray(Type[]::new));

now you get no warnings, you don't need the cast, all is well. In this scenario at runtime the system does know how to make an array of Type (because you pass in a lambda that makes it). An alternative is this:

return operators.get(operatorIndex).operation(thisArgs.toArray(new Type[0]));

the provided array here (new Type[0]) is used only to get the component type, then the array is tossed in the garbage (it's a very short lived object, so it's free garbage, fortunately), and a new one is made, but now it WILL have the proper type; it'll be a Type[], and not an Object[].

TL;DR: Do not, ever, use collections' .toArray() method. It still exists, and will continue to exist... because of the backwards compatibility thing I talked about. That's the only reason.

Collection.toArray() java.lang.ClassCastException

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

Java, converting ArrayList to array (toArray) cannot be casted?

Try below to get the array of same type as List

    List<Depot> depts = new ArrayList<Depot>();
depts.add(new Depot(1, 2));
depts.add(new Depot(1, 2));
depts.add(new Depot(1, 2));
Depot[] depots = depts.toArray(new Depot[depts.size()]);

Why there is a ClassCastException when i try to convert object[] to Student[]?

Why Student[] sList = (Student[]) pList.toArray(); wont work?

Some info from the link right below:

In Java, generic type exists at compile-time only. At runtime
information about generic type (like in your case Student) is
removed and replaced with Object type (take a look at type erasure).
That is why at runtime toArray() have no idea about what precise type
to use to create new array, so it uses Object as safest type, because
each class extends Object so it can safely store instance of any
class.

Now the problem is that you can't cast instance of Object[] to Student[].

The JVM doesn't know (or more precisely, it is not allowed to do that. If it could do that, it would violate Java type safety) how to blindly downcast Object[] (the result of
toArray()) to Student[]. To let it know what your desired object type
is, you can pass a typed array into toArray().

Solution: pList.toArray(Student[]::new)

More info: Converting 'ArrayList<String> to 'String[]' in Java

JAVA casting list of strings to string array

Use it like this - String [] myArray = myList.toArray(new String[myList.size()]);

java: (String[])List.toArray() gives ClassCastException

This is because when you use

 toArray() 

it returns an Object[], which can't be cast to a String[] (even tho the contents are Strings) This is because the toArray method only gets a

List 

and not

List<String>

as generics are a source code only thing, and not available at runtime and so it can't determine what type of array to create.

use

toArray(new String[v2.size()]);

which allocates the right kind of array (String[] and of the right size)



Related Topics



Leave a reply



Submit