在运行时获取泛型的类型
来源:互联网 发布:65是什么意思网络用语 编辑:程序博客网 时间:2024/05/16 17:02
转自:http://www.dongliu.net/post/5896921377931264
都Java 1.5在加入泛型支持时,为了保持兼容,采用的是擦除法实现,泛型的定义只在编译的时候有效,编译之后是没有保留泛型的类型信息的,运行时所有的instance都当作限界类型来使用,没有指定限界类型是则是当作Object类型。所以,通常是无法在运行时获得泛型的类型活实例化泛型类的,如下面的代码都无法通过编译:
public class Test<T> {
public Test(){
T t = new T(); // error
Class<T> clazz = T.class; //error
T[] ts = new T[10]; //error
}
}
然而,擦除法的实现存在一些特列,在这些特例情况下,Java会记录泛型的类型信息,并且可以通过Api来获取的。比如在各种持久化框架中广泛使用的BaseDao泛型类的写法,就利用一个泛型继承的特例:public Test(){
T t = new T(); // error
Class<T> clazz = T.class; //error
T[] ts = new T[10]; //error
}
}
public class BaseDAO<U> {
private Class<U> entityClass;
protected BaseDAO() {
// 获取泛型类型
Type type = getClass().getGenericSuperclass();
Type[] trueType = ((ParameterizedType) type).getActualTypeArguments();
this.entityClass = (Class<U>) trueType[0];
}
public U getById(Serializable id){
PersistenceManager pm = getPersistenceManager();
pm.setDetachAllOnCommit(true);
U object;
try{
object = pm.getObjectById(entityClass, id);
}catch (JDOObjectNotFoundException e) {
object = null;
}finally{
pm.close();
}
return object;
}
}
public class TagDAO extends BaseDAO<Tag>{
}
代码的关键是getGenericSuperclass方法,这个方法返回的类型为ParameterizedType,里面可以通过getActualTypeArguments来获取泛型的真正类型。这样的特例是违背了擦除法的实现思想的,这也是Java为保证类型系统完整而不得不做的妥协。private Class<U> entityClass;
protected BaseDAO() {
// 获取泛型类型
Type type = getClass().getGenericSuperclass();
Type[] trueType = ((ParameterizedType) type).getActualTypeArguments();
this.entityClass = (Class<U>) trueType[0];
}
public U getById(Serializable id){
PersistenceManager pm = getPersistenceManager();
pm.setDetachAllOnCommit(true);
U object;
try{
object = pm.getObjectById(entityClass, id);
}catch (JDOObjectNotFoundException e) {
object = null;
}finally{
pm.close();
}
return object;
}
}
public class TagDAO extends BaseDAO<Tag>{
}
Jackson json中反序列化时,可以通过TypeReference传递容器中的泛型类型,也是利用了泛型继承的特例:
Map<Integer, ApkBean> map = mapper.readValue(jsonData, new TypeReference<Map<Integer, ApkBean>>(){});
TypeReference是一个泛型抽象类,在readValue的第二个方法中,传入了TypeReference的一个匿名子类实例,由此带入了Map的泛型信息。由于是两级泛型的嵌套,具体的情况其实更复杂一些,有兴趣的可以看看Jackson代码中TypeReference和TypeFactory的实现。除了泛型继承这种情况之外,还有另外两个特例,也可以获取ParameterizedType类型,继而获取到泛型的类型。一个是类的field可以通过getGenericType来获取:
public class Test {
private Map<String, Number> map;
public static void main(String[] args) throws NoSuchFieldException {
Class<?> clazz = Test.class;
Field field = clazz.getDeclaredField("map");
//取得泛型类型
Type type = field.getGenericType();
ParameterizedType ptype = (ParameterizedType)type;
System.out.println(ptype.getActualTypeArguments()[0]);
System.out.println(ptype.getActualTypeArguments()[1]);
}
}
另外就是方法的泛型参数可以通过getGenericParameterTypes来获取:private Map<String, Number> map;
public static void main(String[] args) throws NoSuchFieldException {
Class<?> clazz = Test.class;
Field field = clazz.getDeclaredField("map");
//取得泛型类型
Type type = field.getGenericType();
ParameterizedType ptype = (ParameterizedType)type;
System.out.println(ptype.getActualTypeArguments()[0]);
System.out.println(ptype.getActualTypeArguments()[1]);
}
}
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = Test.class;
Method method = clazz.getDeclaredMethod("getGenericSample", Collection.class);
//取得泛型类型参数集
Type[] type = method.getGenericParameterTypes();
ParameterizedType ptype = (ParameterizedType)type[0];
type = ptype.getActualTypeArguments();
System.out.println(type[0]);
}
public void getGenericSample(Collection<Number> collection){
}
}
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = Test.class;
Method method = clazz.getDeclaredMethod("getGenericSample", Collection.class);
//取得泛型类型参数集
Type[] type = method.getGenericParameterTypes();
ParameterizedType ptype = (ParameterizedType)type[0];
type = ptype.getActualTypeArguments();
System.out.println(type[0]);
}
public void getGenericSample(Collection<Number> collection){
}
}
这两种特例的实用价值比较小,实际的代码hack中也比较少见。
0 0
- 在运行时获取泛型的类型
- 在运行时获取泛型的类型
- 如何在运行时获取泛型的类型
- Java 运行时如何获取泛型参数的类型
- Java 运行时如何获取泛型参数的类型
- Java 运行时如何获取泛型参数的类型
- java在运行时获取泛型实例的方法
- 如何用C++获取运行时变量的类型
- 获取运行时泛型的实际类型
- 获取运行时期的对象类型
- 获取泛型的类型
- 得到运行时类的泛型类型。
- 在运行时获取ibatIS执行的sql
- 关于IList类型与IList<T>在运行时类型转换失败的问题
- 获取在接口或者类上定义的泛型类型
- 获取运行在手机前台的应用程序
- 在编译期间获取类型的信息
- 在java中获取变量的类型
- opencv6.3-imgproc图像处理模块之边缘检测
- GEC210(S5PV210)裸机驱动之中断系统
- Visual Studio 2013 无法启动 IIS Express 的解决办法,新建web项目时出错,系统找不到指定文件
- 【精益创业入门】什么是精益创业?
- SQL Server 查询优化(测试03)执行计划优化
- 在运行时获取泛型的类型
- 【协议分析】ARP协议
- contextConfigLocation在spring中的作用
- 冬来,落雪为念
- ndk版本的下载
- Xfce4 在Ubuntu上
- 冬来,落雪为念
- [Leetcode]Remove Duplicates from Sorted Array II
- 声明和定义变量、const限定符和引用、简单的类类型需注意点