К сожалению, решение Кристофа, как написано, работает только в очень ограниченных обстоятельствах. [РЕДАКТИРОВАТЬ: как прокомментировано ниже, я больше не помню свои аргументы в пользу этого предложения, и оно, вероятно, неправильно: «Обратите внимание, что это будет работать только в абстрактных классах, в первую очередь».] Следующая трудность заключается в том, что g()
работает только от DIRECT подклассы A
. Мы можем это исправить, хотя:
private Class<?> extractClassFromType(Type t) throws ClassCastException {
if (t instanceof Class<?>) {
return (Class<?>)t;
}
return (Class<?>)((ParameterizedType)t).getRawType();
}
public Class<B> g() throws ClassCastException {
Class<?> superClass = getClass(); // initial value
Type superType;
do {
superType = superClass.getGenericSuperclass();
superClass = extractClassFromType(superType);
} while (! (superClass.equals(A.class)));
Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0];
return (Class<B>)extractClassFromType(actualArg);
}
Это будет работать во многих ситуациях на практике, но не ВСЕ время. Рассмотрим:
public class Foo<U,T extends Collection<?>> extends A<T> {}
(new Foo<String,List<Object>>() {}).g();
Это выдаст ClassCastException
, потому что аргумент типа здесь вовсе не Class
или ParameterizedType
; это TypeVariable
T
. Так что теперь вы застряли, пытаясь выяснить, какой тип T
должен был стоять и так далее по кроличьей норе.
Я думаю, что единственный разумный общий ответ - это что-то похожее на первоначальный ответ Николаса - в общем, если вашему классу нужно создавать экземпляры объектов какого-то другого класса, который неизвестен во время компиляции, пользователи вашего класса должны передавать его класс литерал (или, возможно, Фабрика) для вашего класса в явном виде и не полагаться исключительно на дженерики.