Java generics, получите класс <T> общего параметра

У меня есть абстрактный класс:

public abstract class RootProcessor<T> {
    Class<T> clazz;
}

Мне нужно заполнить ClassT clazz; детьми RootProcessor - каждый ребенок имеет свой собственный T

Я нашел только одно решение, но ему нужен аргумент компилятора -Xlint:unchecked

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

Это лучшее решение? Можем ли мы сделать то же самое без -Xlint:unchecked?

Ответ 1

Типичный, но коллиматорный способ сделать это - передать токен Class<T> ", где компилятор может его увидеть":

public abstract class RootProcessor<T> {
    Class<T> clazz;

    protected RootProcessor<T>(Class<T> clazz) {
        this.clazz = clazz;
    }
}

public class FooProcessor extends RootProcessor<Foo> {
    public FooProcessor() {
        super(Foo.class);
    }
}

Если вы делаете непроверенный актерский состав, но вы "знаете, что делаете", и хотите, чтобы компилятор прекратил жаловаться, правильный подход будет локализовать не-тип-безопасный, но-вы-know-they- рабочие биты и используя @SuppressWarnings:

public abstract class RootProcessor<T> {
    Class<T> clazz;
    { initClazz(); }

    @SuppressWarnings("unchecked")
    private void initClazz() {
        // the usual verbiage you already have in your question
        this.clazz = this.getClass().getGenericSuperclass().yadda().blah();
    }
}

(я не буду держать это против вас: P)

Ответ 2

Есть сообщение с тем же вопросом: Отражение дженериков

И класс, который его реализует: TypeArgumentsUtils.java

Пример приведен в unit test.

Итак, если у вас есть этот класс:

public class BarProcessor extends RootProcessor<Bar> {
    public BarProcessor() {
    }
}

чем вы получите первый параметр с помощью:

Class barClass = TypeArgumentsUtils.getFirstTypeArgument(
        RootProcessor.class, BarProcessor.class);