Why Does List<String>.Toarray() Return Object[] and Not String[]? How to Work Around This

why does ListString.toArray() return Object[] and not String[]? how to work around this?

You need to pass in an array so its runtime type can be used as a hint by toArray. Try toArray(new String[0]) instead. You can also pass in a pre-sized array.

To understand, consider what type erasure would have to do to make

new T[4]

work. If Java allowed that, the best it could do post erasure is

new Object[4]

Most toArray implementations use java.lang.reflect.Array to construct an output array of the right type given a type hint passed as a Class.

Why does ListT.toArray() return generic Object[] instead of T[]?

Flexibility.

The toArray() method without passing any argument returns Object[].

There is a good reason that now you know which type you are expecting and the authors of the method do not know which type of array to return at runtime due to type erasing. So they just let it be the Super type of all the object which is Object and that is why it returns Object[]

If you want to specify your type, they are good and return your specific type :)

String[] aItems= items.toArray(new String[0]);

In what case does casting ArrayListType.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.

toArray() returns object[]

double [] arr = arrList.toArray(new Double[arrList.size()]);

double[] is a different type than Double[]. While Java can convert between double and Double with autoboxing and autounboxing, it cannot convert from Double[] to double[]. You can fix the problem with:

Double [] arr = arrList.toArray(new Double[arrList.size()]);

What is reason for list couldn't convert into array?

List.toArray() is a method in the interface List, and the documentation does not specify what kind of array is returned by the method. However, unlike other answers suggested, the List.toArray() method cannot return an array of the generic type of the list, because the generic type of a list is not known at runtime.

Because of that, all the implementations of List that are built-in to the standard API return an Object[], and not a String[].

However, you are allowed to pass your own pre-allocated array into the method List.toArray(Object[]). If you do that, you are guaranteed to get a return value that has the same element type as the array that you passed in. If the array that you passed in has the same size as the list itself, then that array will be used (otherwise, a new array of the proper size is allocated internally)

This will fix it:

public void method1(List s) {
String[] array = s.toArray(new String[s.size()]); // <-- pass the array as an argument
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}

Convert ArrayListString to String[] array

Use like this.

List<String> stockList = new ArrayList<String>();
stockList.add("stock1");
stockList.add("stock2");

String[] stockArr = new String[stockList.size()];
stockArr = stockList.toArray(stockArr);

for(String s : stockArr)
System.out.println(s);

Why does CollectionE#toArray() not return E[]?

It's because an array of type T cannot be instantiated without knowing the type Class<T>. Contrast this with toArray(T[] array), which has the following source (example from LinkedList). Notice that the passed-in array is used not only as a possible container, but to possibly instantiate a new array of that type. This code throws an exception if T is not a superclass of E; if objects can't be added to the array.

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;

if (a.length > size)
a[size] = null;

return a;
}


Related Topics



Leave a reply



Submit