如何使用反射和Guava TypeToken实例化参数化类的Class对象

时间:2014-12-02 22:37:04

标签: java generics reflection guava

我正试图为一个用泛型类型参数参数化的类拉出一些Guava TypeToken魔法,但是当我试图通过{{1}实例化时,我得到了ClassNotFoundException方法。

Class.forName(String)

我得到了这个例外:

“无法找到public class EnumeratedMenu<E extends Enum<E>,T extends EnumeratedBean<E>> { private final TypeToken<EnumeratedMenu<E,T>> typeToken = new TypeToken<EnumeratedMenu<E,T>>(getClass()) { }; private Class<T> getBean() { TypeToken<?> genericBeanParam = typeToken.resolveType(EnumeratedMenu.class.getTypeParameters()[1]); try { //This generates a ClassNotFoundException because of the generic type parameter that EnumeratedBean has. return (Class<T>)Class.forName(genericBeanParam.getType().getTypeName()); } catch(ClassNotFoundException e) { log.error("Unable to find the class definition for {}", genericBeanParam.getType().getTypeName()); log.catching(e); } } }

的类定义

EnumeratedBean<ContextMenuOption$ContextType>ContextMenuOption$ContextType的通用enum参数的运行时类型。我如何获得我想要的类对象?

澄清:

我需要构造类的实例以与构建器对象一起使用,该构建器对象将构造如下所示的菜单选项:

EnumeratedBean

2 个答案:

答案 0 :(得分:4)

你到底想要做什么?

您永远无法获得代表Class<T>等通用类型的EnumeratedBean<ContextMenuOption$ContextType>对象,因为Class只能代表{{1}这样的原始类型}}

可能有其他方法可以达到您想要的结果,但目前还不清楚您想要的结果。例如,您想要使用EnumeratedBean返回的内容是什么?也许可以在没有中间Class对象的情况下

修改

由于看起来您想要的是能够创建Class的实例,以下是使用T进行操作的示例:

TypeToken

答案 1 :(得分:1)

这是不可能的,因为总是只有一个Class,无论参数化如何。这就是Java泛型如何使用类型擦除。 有关如何以及为何的详细说明,您可能需要阅读:

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html

但是对于实例化,你只需要使用你已经拥有的Class;并按照你想要的方式转换泛型类型签名。

这意味着,例如,您实际上可以这样做:

List<String> strings = new ArrayList<String>();
List<Integer> numbers = (List<Integer>)(List<?>) strings;
numbers.add(Integer.valueOf(12));

没有运行时异常。没有真正的运行时信息限制内容;只有隐式投射。但是,如果您尝试过,则会收到运行时异常:

String str = strings.get(0);

因为虽然基础List乐意接受任何java.lang.Object,但访问代码具有“隐藏”强制转换,这将触发异常。

因此,实例化可能会起作用:

List<String> s = (List<String>) ArrayList.class.newInstance();

但使用你想要的任何通用类型。

编辑:

如果需要Guava的TypeToken,它的javadocs建议您应该使用getRawType()获取原始类,或者使用constructor()直接创建实例。