Java

Generics

Unchecked Casts

Say, we have a list of strings:

List<String> ls = Arrays.asList("One", "Two", "Three");

Since List<Object> is not a superclass of List<String> in Java, it is illegal to do things like this:

List<Object> lo = ls; // compile-time error!

At the same time this is legal:

List<Object> lo = (List<Object>)(List<?>)ls; // uchecked cast, but compiles

Why it is so? Well… Since List<?> is a supertype of all parametrized List types it is allowed to downcast List<String> to it. It is also allowed to upcast an instance of List<?> to any of its subtypes, but this is a potentially dangerous procedure and the compiler yields a warning.

Wildcards vs Raw Types

What’s the difference between Collection<?> and Collection? After type erasure both of them will be just collection of objects (not Collection<Object>!) But the compiler considers Collection<?> to be a collection of objects of the same type, while Collection can contains objects of different types. This means that the first option is a bit more type-safe.

Another difference is that Collection<?> is a supertype for all parametrized Collection types.

Exploring Generics with -XD-printflat

There is a neat hidden option -XD-printflat of the javac compiler, which allows you to generate the interim representation of parametrized classes. Applying this option shows you how you generic clases look after the type erasure. For example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Box<T> {
 private T myObj;

 public Box(T obj) {
     myObj = obj;
 }

 public T get() {
     return myObj;
 }
}

been compiled with the command:

$ javac -XD-printflat -d output_dir Box.java

generates output_dir/Box.java file with the following content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Box {
 private Object myObj;

 public Box(Object obj) {
     super();
     myObj = obj;
 }

 public Object get() {
     return myObj;
 }
}

That’s super useful when you need to understand how generics work or debugging some type erasure related issue.