Java 如何使用反射和Guava TypeToken为参数化类实例化类对象
我试图为一个用泛型类型参数参数化的类实现一些GuavaJava 如何使用反射和Guava TypeToken为参数化类实例化类对象,java,generics,reflection,guava,Java,Generics,Reflection,Guava,我试图为一个用泛型类型参数参数化的类实现一些GuavaTypeToken魔术,但是当我试图通过class.forName(String)方法实例化它时,我得到了一个ClassNotFoundException public class EnumeratedMenu<E extends Enum<E>,T extends EnumeratedBean<E>> { private final TypeToken<EnumeratedMenu<
TypeToken
魔术,但是当我试图通过class.forName(String)
方法实例化它时,我得到了一个ClassNotFoundException
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
)的Class
对象,因为Class
只能表示原始类型(如EnumeratedBean
)
可能还有其他方法可以达到你想要的结果,但目前还不清楚你想要的结果是什么。例如,您想使用返回的类
做什么?也许在没有中间类
对象的情况下可以做到这一点
编辑:
因为看起来您想要的是能够创建T
的实例,下面是一个使用TypeToken
的示例:
public class EnumeratedMenu<E extends Enum<E>, T extends EnumeratedBean<E>> {
// Just get the type of T, that's what we care about here
private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {};
private T create() {
try {
// Using the raw type Class object for the token to
// get at its default constructor.
return typeToken.constructor(typeToken.getRawType().getConstructor())
.invoke(null);
} catch (Exception e) {
// ...
}
}
}
公共类枚举菜单{
//只要得到T的类型,这就是我们关心的
private final-TypeToken-TypeToken=new-TypeToken(getClass()){};
private T create(){
试一试{
//使用令牌的原始类型类对象
//获取其默认构造函数。
返回typeToken.constructor(typeToken.getRawType().getConstructor())
.invoke(空);
}捕获(例外e){
// ...
}
}
}
你到底想在这里做什么
您永远无法获得表示泛型类型(如EnumeratedBean
)的Class
对象,因为Class
只能表示原始类型(如EnumeratedBean
)
可能还有其他方法可以达到你想要的结果,但目前还不清楚你想要的结果是什么。例如,您想使用返回的类
做什么?也许在没有中间类
对象的情况下可以做到这一点
编辑:
因为看起来您想要的是能够创建T
的实例,下面是一个使用TypeToken
的示例:
public class EnumeratedMenu<E extends Enum<E>, T extends EnumeratedBean<E>> {
// Just get the type of T, that's what we care about here
private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {};
private T create() {
try {
// Using the raw type Class object for the token to
// get at its default constructor.
return typeToken.constructor(typeToken.getRawType().getConstructor())
.invoke(null);
} catch (Exception e) {
// ...
}
}
}
公共类枚举菜单{
//只要得到T的类型,这就是我们关心的
private final-TypeToken-TypeToken=new-TypeToken(getClass()){};
private T create(){
试一试{
//使用令牌的原始类型类对象
//获取其默认构造函数。
返回typeToken.constructor(typeToken.getRawType().getConstructor())
.invoke(空);
}捕获(例外e){
// ...
}
}
}
这是不可能做到的,因为无论参数化如何,始终只有一个类。这就是Java泛型如何处理类型擦除。
有关如何以及为什么这样做的详细说明,您可能需要阅读:
但是对于实例化,您只需要使用已有的类
;并按您想要的方式强制转换泛型类型签名
例如,这意味着您实际上可以:
List<String> strings = new ArrayList<String>();
List<Integer> numbers = (List<Integer>)(List<?>) strings;
numbers.add(Integer.valueOf(12));
因为当底层List
愉快地接受任何java.lang.Object
s时,访问代码具有“隐藏”类型转换,这将触发异常
因此,实例化的工作方式可能类似于:
List<String> s = (List<String>) ArrayList.class.newInstance();
List s=(List)ArrayList.class.newInstance();
但是使用任何你想要的泛型类型
编辑:
如果需要Guava的TypeToken
,它的javadocs建议您要么使用getRawType()
获取原始类,要么直接使用constructor()
创建实例,这是不可能的,因为无论参数化如何,总是只有一个类。这就是Java泛型如何处理类型擦除。
有关如何以及为什么这样做的详细说明,您可能需要阅读:
但是对于实例化,您只需要使用已有的类
;并按您想要的方式强制转换泛型类型签名
例如,这意味着您实际上可以:
List<String> strings = new ArrayList<String>();
List<Integer> numbers = (List<Integer>)(List<?>) strings;
numbers.add(Integer.valueOf(12));
因为当底层List
愉快地接受任何java.lang.Object
s时,访问代码具有“隐藏”类型转换,这将触发异常
因此,实例化的工作方式可能类似于:
List<String> s = (List<String>) ArrayList.class.newInstance();
List s=(List)ArrayList.class.newInstance();
但是使用任何你想要的泛型类型
编辑:
如果需要Guava的TypeToken
,它的javadocs建议您要么使用getRawType()
获取原始类,要么直接使用constructor()创建实例
我试图将对象实例化为参数化类型,并使用生成器类设置其字段,该生成器类将使用bean字段中的值来构造菜单选项。@Selena底层的类对象从不因泛型类型而异:例如,List
与List
完全相同(请随意测试,以验证通过List.getClass()
获得的实际Class
对象是否相同)。这也意味着通过反射进行实例化是完全相同的;大多数泛型类型都是由编译器插入类型转换来处理的,并且没有实际的运行时差异。这意味着您将无法构造不同的类:它们不存在。您需要使用已擦除的现有类型Class
@StaxMan:ok。那么如何从Guava类型标记中获取类型擦除类的实例呢;虽然您可以使用“constructor()”来实例化传递的类型?@StaxMan:谢谢。这就是我需要的。因此,您应该将此细节添加到您的a中