温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

利用Java泛型怎么获取T.class

发布时间:2021-01-14 14:51:13 来源:亿速云 阅读:598 作者:Leah 栏目:编程语言

利用Java泛型怎么获取T.class?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

泛型的四点作用:

第一是泛化,可以拿个T代表任意类型。 但GP是被C++严苛的静态性逼出来的,落到Java、C#这样的花语平原里----所有对象除几个原始类型外都派生于Object,再加上Java的反射功能,Java的Collection库没有范型一样过得好好的。

第二是泛型 + 反射,原本因为Java的泛型拿不到T.class而觉得泛型没用,最近才刚刚学到通过反射的API来获取T的Class,后述。

第三是收敛,就是增加了类型安全,减少了强制类型转换的代码。这点倒是Java Collection历来的弱项。

第四是可以在编译期搞很多东西,比如MetaProgramming。但除非能完全封闭于框架内部,框架的使用者和扩展者都不用学习这些东西的用法,否则那就是自绝于人民的票房毒药。C++的MetaProgramming好厉害吧,但对比一下Python拿Meta Programming生造一个Class出来的简便语法,就明白什么才是真正的叫好又叫座。

所以,作为一个架构设计师,应该使用上述的第2,3项用法,在框架类里配合使用反射和泛型,使得框架的能力更强; 同时采用收敛特性,本着对人民负责的精神,用泛型使框架更加类型安全,更少强制类型转换。

擦拭法避免了Java的流血分裂 :

大家经常骂Java GP的擦拭法实现,但我觉得多亏于它的中庸特性---如果你用就是范型,不用就是普通Object,避免了Java阵营又要经历一场to be or not to be的分裂。
最大的例子莫过Java 5的Collection 框架, 比如有些同学坚持认为自己不会白痴到类型出错,而且难以忍受每个定义的地方都要带一个泛型定义List〈Book〉,不用强制类型转换所省下的代码还不够N处定义花的(对了,java里面还没有tyepdef.....),因此对范型十分不感冒,这时就要齐齐感谢这个搽拭法让你依然可以对一个泛型框架保持非泛型的用法了...

<<干货来了!!!!!!>>

通过反射获得 T.class:

abstract public class BaseHibernateEntityDao<T> extends HibernateDaoSupport {
    private Class<T> entityClass;
    public BaseHibernateEntityDao() {
      entityClass =(Class<T>) ((ParameterizedType) getClass()
          .getGenericSuperclass()).getActualTypeArguments()[0];
} public T get(Serializable id) { T o = (T) getHibernateTemplate().get(entityClass, id); return o; } }

重点就是这句话:

Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

解释:

1. public Type getGenericSuperclass()

用来返回表示当前Class 所表示的实体(类、接口、基本类型或 void)的直接超类的Type。如果这个直接超类是参数化类型的,则返回的Type对象必须明确反映在源代码中声明时使用的类型。比如:

import java.lang.reflect.ParameterizedType; 
public class GT1 extends GT2<Integer>{ 
  public static void main(String[] args) { 
    System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass())); 
  } 
}

则输出结果即为:

GT2<java.lang.Integer>

如果此Class代表的是Object 类、接口、基本类型或 void,则返回 null。。如果此对象表示一个数组类,则返回表示 Object 类的 Class 对象。

2. public Type[] getGenericInterfaces()

与上面那个方法类似,只不过Java的类可以实现多个接口,所以返回的Type必须用数组来存储。

以上两个方法返回的都是Type对象或数组,在我们的这个话题中,Class都是代表的参数化类型,因此可以将Type对象Cast成ParameterizedType对象。而 ParameterizedType对象有一个方法, getActualTypeArguments()。

public Type[] getActualTypeArguments()

用来返回一个Type对象数组,这个数组代表着这个Type声明中实际使用的类型。接着使用上面的例子:

import java.lang.reflect.ParameterizedType; 
public class GT1 extends GT2<Integer>{ 
  public static void main(String[] args) { 
  System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()).getActualTypeArguments()[0]); 
  } 
}

这次的显示结果将是:class java.lang.Integer

因此,我们可以通过继承+反射的方法,来的到T.class。

需要说明的是,江南白衣使用的方法是将关键语句

 Class < T > entityClass = (Class < T > ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ];

放在了超类,也就是声明泛型的那个类的构造方法中。这样一来,子类在继承具有泛型的超类时,会自动调用超类的构造方法。在此超类的构造方法中,调用的getClass返回的是子类的Class类型(与通常的重写机制有悖,呵呵,有待深究,但测试结果确是如此),则在子类中就无需再显式地使用getGenericInterfaces()和getGenericSuperclass()等方法了。

接着,再使用(Class<T>)对 getActualTypeArguments()返回的元素做casting,即可得到所谓的T.class。

泛型之后,所有BaseHibernateEntityDao的子类只要定义了泛型,就无需再重载getEnttityClass(),get()函数和find()函数,销益挺明显的,所以SpringSide的Dao基类毫不犹豫就泛型了。

不过擦拭法的大棒仍在,所以子类的泛型语法可不能乱写,最正确的用法只有:

public class BookDao extends BaseHibernateEntityDao<Book>

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI