[泛型经典]Java5泛型的用法,T.class的获取和为擦拭法站台

本文深入探讨了Java泛型的四点核心作用:泛化、泛型与反射结合、收敛和元编程,并通过实例展示了如何利用反射获取泛型类的Class,以及如何在框架设计中合理应用泛型以增强类型安全和减少强制类型转换。重点介绍了擦洗法在处理泛型框架的灵活性与类型安全性之间的权衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java 5的泛型语法已经有太多书讲了,这里不再打字贴书。GP一定有用,不然Java和C#不会约好了似的同时开始支持GP。但大家也清楚,GP和Ruby式的动态OO语言属于不同的意识形态,如果是一人一票,我想大部分的平民程序员更热衷动态OO语言的平白自然。但如果不准备跳槽到支持JSR223的动态语言,那还是看看GP吧。

胡乱总结泛型的四点作用:
第一是泛化,可以拿个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:

不知为何书上不怎么讲这个,是差沙告诉我才知道的,最经典的应用见Hibernate wiki的 Generic Data Access Objects, 代码如下:
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);
}
}

精华就是这句了:
Class < T > entityClass = (Class < T > ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ];

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

不过擦拭法的大棒仍在,所以子类的泛型语法可不能乱写,最正确的用法只有:
public class BookDao extends BaseHibernateEntityDao < Book >

Java中,使用的方法可以通过参数来传入。如果您希望获取一个类的对象(例如一个类或接口的Class对象),可以使用通配符类参数来达到这个目的。具体步骤如下: 1. 创建一个带有参数的方法,并在方法内部声明一个变量作为类参数的类,例如使用类参数T来代替实际的。 ```java public static <T> Class<T> getClass(T obj) { return obj.getClass(); } ``` 在这个方法中,我们将一个对象obj作为方法的参数,并将其转换为Class对象。 2. 在调用该方法时,您需要传递一个具有实际的对象作为参数。例如,如果您有一个集合List<String>,您可以调用该方法并传入一个String对象作为参数。 ```java List<String> list = new ArrayList<>(); Class<String> stringClass = getClass(list.get(0)); ``` 在这个例子中,我们获取了列表中的第一个元素(类为String),并将其传递给方法以获取Class对象。 另外,需要注意的是,由于通配符类参数是在编译时使用的,因此如果您传递了一个没有在代码中明确指定的的对象给方法,那么该方法可能会编译失败或返回错误的Class对象。因此,在调用该方法时需要确保传递的对象是正确的。 如果您想要获取一个对象的Class对象并且不关心它的具体类,那么可以使用通配符类参数并直接返回该对象的Class对象。例如: ```java public static Class<?> getClass(Object obj) { return obj.getClass(); } ``` 在这个例子中,我们使用了Type变量的别名而不是类参数T。请注意,这个方法可能会返回任何对象的Class对象,而不仅仅是对象的Class对象。如果您只关心Class对象,那么最好使用上面的示例中的示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值