java – Infer class type from a generic

Question:

In the next class I want to assign the clazz attribute the class type, inferring it from the list informed in the constructor.

class Foo<T> {
    private Class<T> clazz;

    Foo(List<T> list) {
        //this.clazz = tipo da classe inferido a partir da lista
    }

    ...
}

My first attempt was to use the list.getClass() method which turned out to be wrong, as the value returned by the method was java.util.ArrayList .

How to infer the type of a bean informed in an ArrayList? Is it possible to make this kind of inference from the parameter, as in the example? If so , what would it be like? If not , what are the possibilities, ie how to adjust this class in order to assign the correct value to the clazz attribute?

Answer:

One possible trick is to switch an instance of your class:

Foo<Integer> x = new Foo<Integer>(new ArrayList<Integer>());

By a subclass of it (in this case an anonymous class):

Foo<Integer> x = new Foo<Integer>(new ArrayList<Integer>()){}; 
//                                             Repare no {} ^

Once that's done you can use the strategy mentioned in this SOen answer to infer the superclass's generic types:

this.clazz = (Class<T>) ((ParameterizedType) getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0];

In your case by definition the superclass type will be the list type.

As instantiating the class directly will throw an error at runtime it's worth making Foo abstract:

abstract class Foo<T> {
    private final Class<T> clazz;

    public Foo(List<T> list) {
        this.clazz = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
    }
}

Alternatively we can use the same strategy with the list:

this.clazz = (Class<T>) ((ParameterizedType) list.getClass()
        .getGenericSuperclass()).getActualTypeArguments()[0];
// ... 
List<Integer> t = new ArrayList<Integer>(){};
FooII<Integer> x = new FooII<>(t);

But this seems even more confusing to me (anonymous ArrayList subclasses ???).


Of course, this strategy has limitations… The main one is that <T> has to be a real type. If you build Foo passing another generic type the casts will fail.

Functional version on Ideone

Scroll to Top