前言
平时业务中,有时候要做多态,用到泛型,又要反序列化,或者其他需要,在公共部分中,要知道当前泛型在具体子类实现的类,该如何做呢?
比如,抽象类AbstractHandler<T>
想要知道StringHandler<String>
中的String,T.class
是行不通的,java的泛型是类型擦除,只知道泛型的上界。
要获得具体的泛型的class,可以通过继承关系中残留的信息来获取,具体来说,通过读取Class文件中的签名信息。
当然,还有一些其他的方法,比如如果有具体的对象,取出来反射一下可以获得,亦或者将class作为参数直接传进来,这都是可以的,但不够简洁。
实践
Spring自带工具
public interface IService<T> {
default Class<T> getClazz() {
return (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), IService.class);
}
}
自己的接口继承此接口即可,在实现自己接口的子类中就可以调用。
如果子类没有具体的类型会返回null,支持多继承,会一直向父类查找,直到找到将泛型实现为具体的类。
反射
public abstract class AbstractHandler<T> implements HandlerInterface<T> {
public void test() {
……
Class entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
……
}
}
抽象类的子类通过抽象类的方法获取泛型类型。
getClass()
获取当前类,getGenericSuperclass()
获取当前类带泛型的父类,getActualTypeArguments()
获取具体的泛型参数数组。
不支持多重继承。
其他可参考的实现
com.alibaba.fastjson.TypeReference
package com.alibaba.fastjson;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.alibaba.fastjson.util.TypeUtils;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class TypeReference<T> {
static ConcurrentMap<Type, Type> classTypeCache = new ConcurrentHashMap(16, 0.75F, 1);
protected final Type type;
public static final Type LIST_STRING = (new TypeReference<List<String>>() {
}).getType();
protected TypeReference() {
Type superClass = this.getClass().getGenericSuperclass();
Type type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
Type cachedType = (Type)classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = (Type)classTypeCache.get(type);
}
this.type = cachedType;
}
public Type getType() {
return this.type;
}
}
带泛型的类在使用fastjson
反序列化的时候需要我们传一个匿名TypeReference
子类,就是通过父类一系列反射的操作获得具体类的, Type superClass = this.getClass().getGenericSuperclass(); Type type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
与我们之前自己进行的操作类似,只不过还将类型放入了ConcurrentHashMap
中做了缓存以供后续使用。