现象 1 2 3 4 5 6 Type type = getClass().getGenericSuperclass();if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Class<R> requestClass = (Class<R>) parameterizedType.getActualTypeArguments()[0 ]; ... }
第四行 Class<R> requestClass = (Class<R>) parameterizedType.getActualTypeArguments()[0]
报 java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
错误
这个代码是子类想要拿到泛型参数时出现的类型转换异常
分析 上述问题中的类结构简化如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Request {}public class Request2 extends Request {}public class Request3 extends Request2 {}public abstract class A <R extends Request > { public void requestHandle { Type type = getClass().getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Class requestClass = (Class) parameterizedType.getActualTypeArguments()[0 ]; ... } } } public class B <R extends Request2 > extends A <R> {} public class C extends B <Request3> {}
1/ (new C).requestHandle()
因为 C 继承 B,所以 parameterizedType.getActualTypeArguments()[0]
拿到的其实就是 Request3.class
2/ (new B).requestHandle()
这种情况 parameterizedType.getActualTypeArguments()[0]
返回的是 TypeVariable
,不是 Class 很好理解,因为 B 类的定义是 B,这里很容易因为泛型的类型擦除误认为 parameterizedType.getActualTypeArguments()[0]
会返回 Request2.class
解决 仔细观察 TypeVariable
接口定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public interface TypeVariable <D extends GenericDeclaration > extends Type , AnnotatedElement { Type[] getBounds(); D getGenericDeclaration () ; String getName () ; AnnotatedType[] getAnnotatedBounds(); }
我们可以调用 getBounds()
来获取泛型的上边界
最终调整如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void requestHandle { Type type = getClass().getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; Type actualTypeArgument = type.getActualTypeArguments()[0 ]; if (actualTypeArgument instanceof Class) { Class requestClass = (Class) parameterizedType.getActualTypeArguments()[0 ]; ... } else if (actualTypeArgument instanceof TypeVariable) { TypeVariable v = (TypeVariable) actualTypeArgument; Class requestClass = (Class) v.getBounds()[0 ]; ... } ... } }