Редактировать: Вы можете просто захотеть использовать: http://code.google.com/p/gentyref/
Если вы можете гарантировать, что все реализации Awesome<?>
не будут иметь аргументов типа, следующий код должен помочь вам начать [1]:
static void investigate(Object o) {
final Class<?> c = o.getClass();
System.out.println("\n" + c.getName() + " implements: ");
investigate(c, (Type[])null);
}
static void investigate(Type t, Type...typeArgs) {
if(t == null) return;
if(t instanceof Class<?>) {
investigate((Class<?>)t, typeArgs);
} else if(t instanceof ParameterizedType) {
investigate((ParameterizedType)t, typeArgs);
}
}
static void investigate(Class<?> c, Type...typeArgs) {
investigate(c.getGenericSuperclass(), typeArgs);
for(Type i : c.getGenericInterfaces()) {
investigate(i, typeArgs);
}
}
static void investigate(ParameterizedType p, Type...typeArgs) {
final Class<?> c = (Class<?>)p.getRawType();
final StringBuilder b = new StringBuilder(c.getName());
b.append('<');
Type[] localArgs = p.getActualTypeArguments();
if(typeArgs != null && typeArgs.length > 0) {
int i = 0, nextTypeArg = 0;
for(Type local : localArgs) {
if(local instanceof ParameterizedType) {
ParameterizedType localP = (ParameterizedType) local;
b.append(localP.getRawType()).append('<');
b.append(typeArgs[nextTypeArg++]);
b.append('>');
} else if(local instanceof TypeVariable) {
// reify local type arg to instantiated one.
localArgs[nextTypeArg] = typeArgs[nextTypeArg];
b.append(localArgs[nextTypeArg]);
nextTypeArg++;
} else {
b.append(local.toString());
}
b.append(", ");
i++;
}
if(typeArgs.length > 0) {
b.delete(b.length() - 2, b.length());
}
b.append('>');
} else {
String args = Arrays.toString(localArgs);
b.append(args.substring(1, args.length()-1)).append('>');
}
System.out.println(b);
investigate(c, localArgs);
}
Если, однако, будут созданы экземпляры Awesome<?>
или Base<E>
, эта информация о типе будет потеряна из-за удаления. Это можно обойти, как правило, примерно так:
Awesome<?> awesome = new Base<Double>() {};
Обратите внимание на {}
, это создает новый анонимный класс, который реализует (или расширяет) Base<E>
. Этот класс будет иметь параметры типа, доступные для отражения.
Если вы боитесь, что соблюдение этого соглашения будет проблемой, вы можете скрыть конструкторы и использовать только фабричные методы:
class Base<E> implements Awesome<Set<E>> {
public static Base<Number> newNumberInstance() {
return new Base<Number> () {};
}
protected Base() {}
}
Поскольку приведенный выше код не был полностью протестирован, вы можете сделать это. Дело в том, что вы можете найти фактические параметры типа, если ваши требования достаточно строги. Относится ли это к вашей ситуации, решать вам.
[1] Он распечатает все интерфейсы, которые реализует класс, а не только параметры типа Awesome
. Это можно изменить, но я подумал, что пойду на более общий и позволю вам разобраться в специфике. Например, вы захотите проверить это, чтобы понять, что я имею в виду:
investigate(new ArrayList<Integer>());
investigate(new ArrayList<String>() {}); // new anonymous ArrayList class
investigate("");
investigate(new Awesome<Comparable<?>> () {}); // new anonymous implementation of Awesome