javagenericsreification

Why should I care that Java doesn't have reified generics?


This came up as a question I asked in an interview recently as something the candidate wished to see added to the Java language. It's commonly-identified as a pain that Java doesn't have reified generics but, when pushed, the candidate couldn't actually tell me the sort of things that he could have achieved were they there.

Obviously because raw types are allowable in Java (and unsafe checks), it is possible to subvert generics and end up with a List<Integer> that (for example) actually contains Strings. This clearly could be rendered impossible were type information reified; but there must be more than this!

Could people post examples of things that they would really want to do, were reified generics available? I mean, obviously you could get the type of a List at runtime - but what would you do with it?

public <T> void foo(List<T> l) {
   if (l.getGenericType() == Integer.class) {
       //yeah baby! err, what now?

EDIT: A quick update to this as the answers seem mainly to be concerned about the need to pass in a Class as a parameter (for example EnumSet.noneOf(TimeUnit.class)). I was looking more for something along the lines of where this just isn't possible. For example:

List<?> l1 = api.gimmeAList();
List<?> l2 = api.gimmeAnotherList();

if (l1.getGenericType().isAssignableFrom(l2.getGenericType())) {
    l1.addAll(l2); //why on earth would I be doing this anyway?

Solution

  • From the few times that I came across this "need", it ultimately boils down to this construct:

    public class Foo<T> {
    
        private T t;
    
        public Foo() {
            this.t = new T(); // Help?
        }
    
    }
    

    This does work in C# assuming that T has a default constructor. You can even get the runtime type by typeof(T) and get the constructors by Type.GetConstructor().

    The common Java solution would be to pass the Class<T> as argument.

    public class Foo<T> {
    
        private T t;
    
        public Foo(Class<T> cls) throws Exception {
            this.t = cls.newInstance();
        }
    
    }
    

    (it does not necessarily need to be passed as constructor argument, as a method argument is also fine, the above is just an example, also the try-catch is omitted for brevity)

    For all other generic type constructs, the actual type can easily be resolved with a bit help of reflection. The below Q&A illustrate the use cases and possibilities: