Friday, July 1, 2011

Parametrized types and Arrays : Covariance of Arrays

Array types are covariant,  if a type A is a subtype of type B, then A[] is a subtype of B[].

However we have just seen that the parameterised types are not covariant. This leads to an anomaly that cannot be resolved, so Java has the rule that arrays of parameterised types are not allowed. Otherwise we could write code that would potentially cause a ClassCastException, and the whole idea behind the generic types is to remove this possibility so long as no compiler warnings are issued.

Places where covariance of arrays may be harmful:
Case 1 : ArrayStoreException
Apple[] apples = new Apple[1];
Fruit[] fruits = apples;
fruits[0] = new Strawberry();//generates ArrayStoreException

The code indeed compiles, but the error will be raised at runtime as an ArrayStoreException. Because of this behavior of arrays, during a store operation, the Java runtime needs to check that the types are compatible. The check, obviously, also adds a performance penalty that you should be aware of.

Case 2: ClassCastException
List<String>[] wordlists = new ArrayList<String>[10];
ArrayList<Integer> ali = new ArrayList<Integer>();
ali.add( new Integer(123) );
Object[] objs = wordlists;
objs[0] = ali; // No ArrayStoreException
String s = wordlists[0].get(0); // ClassCastException

Once more, generics are safer to use and "correct" this type safety weakness of Java arrays.

In the case you're now wondering why the subtyping relation for arrays is covariant, I'll give you the answer that Java Generics and Collections give: if it was invariant, there would be no way of passing a reference to an array of objects of an unknown type (without copying every time to an Object[]) to a method such as:

void sort(Object[] o);

With the advent of generics, this characteristics of arrays is no longer necessary (as we'll see in the next part of this post) and should indeed by avoided.

No comments:

Post a Comment