Wednesday, June 8, 2011

Answer:Why is toArray() a generic method in Java Collections

At the outset, a special thanks to Joshua Marotti and Kevin from CinJUG to help me get to the solution. This is the solution to the question of my earlier post: Why is toArray() a generic method in Java Collections.

Consider the following scenario:

class Bar{}

class Foo extends Bar{}

List
foos = new ArrayList();
foos.add(new Foo());
foos.add(new Foo());

Bar[] bars = new Bar[ foos.size()];
bars = foos.toArray(bars);


This works fine with the current code but will fail at compile if the method use the class level parameterized type as I had mentioned in the previous post. This is the use case why the method is declared generic. However, it doesn't prevent us from writing the below code which would compile just fine but fail at runtime with ArrayStoreException.

String[] strings = new String[foos.size()];
strings = foos.toArray(strings);


Per Joshua Bloch, we should follow PECS while using generics. Producer Extends, Consumer Super. Its probably the reason, the constructor for classes implementing collections has the extends parameter.

public ArrayList(Collection<? extends E> c)

Unfortunately, the language allows only wildcards for super. If it had supported type declaration with super, we could've solved the ArrayStoreException with the following usage.

<T super E> T[] toArray(T[] a)

On the other hand, I see Scala offers something on this line in scala.collection.immutable.List
def copyToArray [B >: A] (xs: Array[B]): Unit

There's a fabulous explanation on codeidol that discusses generics and collections in a very deep sense (suggested by Joshua Marotti). The chapter about "reification" that has some talks on toarrays and why it is the way it is and is a great read: http://codeidol.com/java/javagenerics/Reification/

No comments: