Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runtime generic type determination

Why this is happening. If I pass anonymous generic class to type determination method - all is good. But if I pass object in this method - console output is E.

public static void main(String[] args) {

    printType(new ArrayList<Integer>() {});
    printType(new ArrayList<Integer>());

}

public static void printType(final List<?> list) {
    System.out.println(((ParameterizedType) list.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}

Console:

class java.lang.Integer

E

Please explain to me.

like image 924
arsen_adzhiametov Avatar asked Sep 27 '13 09:09

arsen_adzhiametov


1 Answers

The first invocation is passing an instance of a anonymous subclass of ArrayList<Integer>. So, it's similar to:

class YourClass extends ArrayList<Integer>

and you invoking the method as:

printType(new YourClass());

The generic superclass of YourClass or the anonymous class in your case is ArrayList<Integer> only. So, that output is clear.


As for your 2nd case, you are passing an instance of ArrayList<Integer> itself. And definition of this class looks like:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

So, the generic superclass here is AbstractList<E>.

Instantiation of generic type share same Class instance:

Note that the all the instantiation of ArrayList share the same class at runtime:

new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass();

The above comparison will give you true. Because both the getClass() invocation gives back to you:

class java.util.ArrayList

See JLS 8.1.2: Generic Classes and Type Parameters:

A generic class declaration defines a set of parameterized types (§4.5), one for each possible invocation of the type parameter section by type arguments. All of these parameterized types share the same class at run time.

For instance, executing the code:

    Vector<String>  x = new Vector<String>(); 
    Vector<Integer> y = new Vector<Integer>(); 
    boolean b = x.getClass() == y.getClass();

will result in the variable b holding the value true.

In other words, getGenericSuperClass() method will not give you the actual type argument you use while instantiating your class, but the type parameter used in the class it is extending. Now, since the generic superclass of java.util.ArrayList is AbstractList<E>. And hence the type parameter you get will be E only.

like image 122
Rohit Jain Avatar answered Oct 08 '22 16:10

Rohit Jain