在java开发中,泛型通常可以用来做两件事儿:
1、检验限制
检验限制添加的或者要处理的数据只能是泛型指定的类型。
比如List<String> list,这个list集合只能添加String类型的数据。
再比如,有一个抽象类Father:
public abstract class Father {
public abstract void execute();
}
有一个类Handler2,只处理继承了Father类的对象:
public class Handler2<T extends Father> {
public void execute(T t){
t.execute();
}
public static void main(String[] args) {
Handler2<Son> handler = new Handler2<Son>();
Son sun = new Son();
handler.execute(sun);
}
}
在Handler2中只是调用了Father子类的execute方法,假如一个类没有继承Father类,则在编译时就会报错:
Handler2<User> handler = new Handler2<User>();
这行代码会报错:
Bound mismatch: The type User is not a valid substitute for the bounded parameter <T extends Father> of the type Handler2<T>
2、根据泛型指定的类型,进行参数的转化
这里所说的参数转换包括两种:一种是类型的强制转换,一种是数据的反序列化。
第一种就不说了(T)obj,这里重点说一下根据泛型进行数据的反序列化:
假设有这么一个需求,你需要设计一个RPC通信框架,RPC通信过程是这样的,在A端,将一个T类型的对象序列化成一个json串,通过socket传给B端,B端接收到这个消息后,将这个Json串反序列化成T类型的对象,进行处理。
先不说消息生产者A端,这里看一下消费者B端,B端不可能为所有类型都单独写一遍基于某个类型的数据接收和数转换的实现方法,而是基于泛型,参数转换类根据指定的泛型。
看下面例子,首先是一个父类Father:
public abstract class Father<T> {
//当泛型是List、Set集合或者是Map时,clazz就是集合的类型,否则就是普通类的类型
public Class clazz;
//当泛型是List、Set类型时,valueClazz就是集合值的类型,Map时就是键值对中值的类型。当泛型为普通类型时,valueClazz为空
public Class valueClazz;
//当泛型是MAP时,keyClazz是键值对中key的类型,当泛型为普通类型时,keyClazz为空
public Class keyClazz;
public ParameterType parameterType;
@SuppressWarnings("unchecked")
public Father(){
//获得当前对象父类的类型,对于Son子类来说,就是Father类。Father类是一个带有泛型的类型
//所以getGenericSuperclass()返回的Type是一个ParameterizedType类型的实例
ParameterizedType paramterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
//getActualTypeArguments用于获得泛型类中<>中的实际类,返回值是一个数组,比如<T,Z>,则数组为{T.class,Z.class}
Type type = paramterizedType.getActualTypeArguments()[0];
//如果泛型中的T也是一个泛型的类型,比如List<User>, collection,Map等泛型
if(ParameterizedType.class.isAssignableFrom(type.getClass())){
ParameterizedType parameterizedType = (ParameterizedType)type;
clazz = (Class<T>) parameterizedType.getRawType();
//如果是map类型,设置key和value的类型
//如果当前类实现了map接口
if(Map.class.isAssignableFrom(clazz)){
keyClazz = (Class) parameterizedType.getActualTypeArguments()[0];
valueClazz = (Class) parameterizedType.getActualTypeArguments()[1];
parameterType = ParameterType.MAP;
//如果是collection集合,则设置集合value的类型
}else{
valueClazz = (Class) parameterizedType.getActualTypeArguments()[0];
parameterType = ParameterType.COLLECTION;
}
}else{
this.clazz = (Class<T>) paramterizedType.getActualTypeArguments()[0];
parameterType = ParameterType.SIMPLE;
}
}
/**
* @Title: receiveAndExecuteMsg
* @Description: 接收并处理消息
* @param @param message
* @param @throws Exception 设定文件
* @return void 返回类型
* @throws
*/
public void receiveAndExecuteMsg(String message)throws Exception{
Object obj = null;
//如果泛型是普通的引用类型
if(parameterType==ParameterType.SIMPLE){
obj = JsonConvertUtil.getObjFromJson(message, clazz);
//如果是List<T>,Set<T>这种泛型
}else if(parameterType==ParameterType.COLLECTION){
obj = JsonConvertUtil.getListFromJosn(message, clazz, valueClazz);
//如果是Map<E,T>这种泛型
}else{
obj = JsonConvertUtil.getMapFromJson(message, clazz, keyClazz, valueClazz);
}
execute((T)obj);
}
/**
* 处理消息
* @Title: execute
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @param t 设定文件
* @return void 返回类型
* @throws
*/
public abstract void execute(T t);
}
然后是两个子类,两个子类都指定了不同的泛型:
public class Son extends Father<List<User>> {
@Override
public void execute(List<User> list) {
System.out.println(list.size()+",name="+list.get(0));
}
}
public class Son2 extends Father<User> {
@Override
public void execute(User user) {
System.out.println("name="+user.getName());
}
}
下面是User实体类和枚举类型ParameterType:
public class User {
private int id;
private String name;
//省略了get/set
}
//标明泛型是什么类型
public enum ParameterType {
SIMPLE("simple", "普通java类"),
COLLECTION("collection", "List,Set等集合"),
MAP("map", "map类型");
private String value;
private String desc;
private ParameterType(String value,String desc){
this.value = value;
this.desc = desc;
}
//.....
}
最后,做一个测试:
public class TestMain {
public static void main(String[] args) {
List<User> userList = new ArrayList<User>();
User user = new User();
user.setId(1);
user.setName("测试1");
userList.add(user);
//模拟一个json消息
String message = JsonConvertUtil.getJsonFromObj(userList);
Son son = new Son();
try {
//接收并处理消息
son.receiveAndExecuteMsg(message);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//测试2
User user2 = new User();
user2.setName("测试2");
//模拟一个json消息
String message2 = JsonConvertUtil.getJsonFromObj(user2);
Son2 son2 = new Son2();
try {
son2.receiveAndExecuteMsg(message2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}