Friday 25 January 2013

Java : Covariant, invariant, reified, erased (Bloch Item 25)

I've compiled a summary of Bloch's item 25 below :

Arrays are covariant i.e., if Sub is a subtype of Super, then the array type Sub[] is a subtype of Super[]. Generics are invariant: for any two distinct types Type1 and Type2, List<Type1> is neither a subtype nor a supertype of List<Type2> [JLS, 4.10; Naftalin07, 2.5].
Object[] objectArray = new Long[1]; 
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException 
List<Object> ol = new ArrayList<Long>(); // Incompatible types 
ol.add("I don't fit in");// Won't compile!
You can’t put a String into a Long container. With an array you find out that you’ve made a mistake at runtime; with a list, you find out at compile time.

Arrays are reified [JLS, 4.7]. This means that arrays know and enforce their element types at runtime. Generics, by contrast, are implemented by erasure [JLS, 4.6]. This means that they enforce their type constraints only at compile time and discard (or erase) their element type information at runtime. Erasure is what allows generic types to interoperate freely with legacy code that does not use generics.

Because of these fundamental differences, arrays and generics do not mix well. For example, it is illegal to create an array of a generic type, a parameterized type, or a type parameter. None of these array creation expressions are legal: new List<E>[], new List<String>[], new E[]. All will result in generic array creation errors at compile time.

Why is it illegal to create a generic array? Because it isn’t typesafe. If it were legal, casts generated by the compiler in an otherwise correct program could fail at runtime with a ClassCastException. This would violate the fundamental guarantee provided by the generic type system.

In summary, arrays and generics have very different type rules. Arrays are covariant and reified; generics are invariant and erased. As a consequence, arrays provide runtime type safety but not compile-time type safety and vice versa for generics. Generally speaking, arrays and generics don’t mix well. If you find yourself mixing them and getting compile-time errors or warnings, your first impulse should be to replace the arrays with lists.

No comments:

Post a Comment