5

toArray method hides <E> passed to Collection<E> interface. Below is the method signature.

<T> T[] toArray(T[] a);

Because of which below is possible. And results into ArrayStoreException

ArrayList<String> string = new ArrayList<String>();
string.add("1");
string.add("2");
Integer intArray[] = new Integer[2];
intArray = string.toArray(intArray);

I wanted to know why was such decision taken? Why was such a case allowed while designing the API ? As anyway this code results in to RuntimeException?

Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72

4 Answers4

3

The toArray method predates the introduction of generics. The original signature of toArray took an arbitrary Object[].

This is the only way, with generics, to accept the same input that was permissible before generics. However, the advantage of taking an arbitrary T[] is that it can return the same array type that it's passed.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • There is also good explanation on [this](http://stackoverflow.com/questions/12355941/collection-toarray-generic-method) thread. I hope I could have accepted both answers :) – Amit Deshpande Oct 28 '12 at 05:57
  • I don't really agree with this argument. If they took the pre-generics code and didn't change it, it would still work, because you would have a raw `ArrayList`, so its `toArray` would take `Object[]`. – newacct Nov 01 '12 at 01:03
  • There are still a couple more funky edge cases I can think of -- for example, if you had a `class FooList extends ArrayList`, and you had the `toArray` method take only a `T[]`, then that one would take only a `Foo[]`. – Louis Wasserman Nov 01 '12 at 01:06
0

When you call, intArray = string.toArray(intArray);, you are expecting it to construct Array of Integer and return the values and hence the return type is T[] i.e. Integer[] in your case.

Calling the method like that doesn't mean you would be able to automatically convert String list into Integer []. The above method invocation will result into java.lang.ArrayStoreException.

This is done to allow usage of convertible classes(base class/subclass) e.g. below:

  List<Integer> list = new ArrayList<Integer>();
  list.add(1);

  Integer[] intArray = new Integer[1];
  intArray = list.toArray(intArray); //Success

  Number [] numArray = new Number[1];
  numArray = list.toArray(numArray);//Success

  Double [] dubArray = new Double[1];
  dubArray = list.toArray(dubArray); //Failure(ArrayStoreException)
Yogendra Singh
  • 33,927
  • 6
  • 63
  • 73
0

When you ask yourself what should be the type of the array in toArray(), the first, most obvious way is to restrict T to be a supertype of E (which includes if T is the same as E): This makes sense -- to be able to copy the elements to an array of a more general element type than our collection. However, although this seems type-safe (i.e. checked at compile time so that no exceptions occur at runtime) at first glance, it is not completely type-safe -- a variable of type T[] can hold any array of type U[] where U is a subtype of T. Thus, it is still possible to get an ArrayStoreException even if we limit T to supertypes of E (and, even if we limit T to be the same as E). Plus, it is difficult to declare this method in such a way that T can only be a supertype of E, since Java does not allow super bounds for type parameters.

The example in the question involves a T that is not a supertype of E. Why should this be allowed? This is not type-safe, and will work only if the elements of the collection are actually subtypes of the actual type of the array. However, it can be argued that this is still no worse than the situation where we restrict T to a supertype of E, or even if we have T be the same as E, because, as explained above, none of those restrictions can make it type-safe either. It's possible to get ArrayStoreException no matter how you declare this method. So why not make it as general as possible, if it's no worse?

newacct
  • 119,665
  • 29
  • 163
  • 224
-1

string.toArray(intArray) returns an array of type String; howver, you desire it to be an array of type Integer. This is going to return the exception you mention, ArrayStoreException due to the types not matching.

Jay Taggart
  • 137
  • 9