现象
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]; ... } ... } }
|