public class Test {
public Test(){
T t = new T(); // error
Class clazz = T.class; //error
T[] ts = new T[10]; //error
}
}
java中泛型的实现时采用擦除法,所以不是第一类型。如若想保留泛型信息,必须采用泛型占位符。
比如常用的开源框架中的DAO层实现。
package sample.jersey.resources.entity;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class BaseDAO {
private Class entityClass;
public Class getEntityClass() {
return entityClass;
}
public void setEntityClass(Class entityClass) {
this.entityClass = entityClass;
}
protected BaseDAO(){
Type type=getClass().getGenericSuperclass();
Type[] trueType = ((ParameterizedType) type).getActualTypeArguments();
this.entityClass = (Class) trueType[0];
System.out.println(" base construct invoked");
}
}
package sample.jersey.resources.entity;
public class TagDao extends BaseDAO {
public static void main(String[] args){
TagDao dao=new TagDao();
System.out.println(dao.getEntityClass());
}
}
Jackson json中反序列化时,可以通过TypeReference传递容器中的泛型类型,也是利用了泛型继承的特例:
Map map = mapper.readValue(jsonData, new TypeReference>(){});
TypeReference是一个泛型抽象类,在readValue的第二个方法中,传入了TypeReference的一个匿名子类实例,由此带入了Map的泛型信息。由于是两级泛型的嵌套,具体的情况其实更复杂一些,有兴趣的可以看看Jackson代码中TypeReference和TypeFactory的实现。
除了泛型继承这种情况之外,还有另外两个特例,也可以获取ParameterizedType类型,继而获取到泛型的类型。一个是类的field可以通过getGenericType来获取:
public class Test {
private Map 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来获取:
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 collection){
}
}
这两种特例的实用价值比较小,实际的代码hack中也比较少见。
下面的代码演示的是内部类的调用和泛型的补偿的另外一个例子。引自jackson里面的genericType里面的实现方法。
package sample.jersey.resources.entity;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import com.sun.jersey.core.reflection.ReflectionHelper;
public class BaseDAO {
@SuppressWarnings("rawtypes")
private Class entityClass;
private Type type;
public BaseDAO() {
Type type = getClass().getGenericSuperclass();
ParameterizedType parameterized = (ParameterizedType) type;
type = parameterized.getActualTypeArguments()[0];
entityClass=getClass(type);
//entityClass=(Class) parameterized.getRawType();
System.out.println(" base construct invoked");
System.out.println(type);
System.out.println(entityClass);
}
@SuppressWarnings("rawtypes")
private static Class getClass(Type type) {
if (type instanceof Class) {
return (Class)type;
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type;
if (parameterizedType.getRawType() instanceof Class) {
return (Class)parameterizedType.getRawType();
}
} else if (type instanceof GenericArrayType) {
GenericArrayType array = (GenericArrayType) type;
return ReflectionHelper.getArrayClass((Class) ((ParameterizedType) array.getGenericComponentType()).getRawType());
}
throw new IllegalArgumentException("Type parameter not a class or " +
"parameterized type whose raw type is a class");
}
public static void main(String[] args) {
BaseDAO> dao=new BaseDAO>() {
public void draw(){
System.out.println(" I am from inherited class.");
}
};
dao.draw();
}
public void draw(){
System.out.println(" I am from father class.");
}
}