[小笔记] Java 反射中用到的 Type 接口
你现在可能会有疑问,在使用 Java
反射中会用到 Type
接口吗?emmmm,你大概率会用到,Class
目标便是完成了 Type
接口,Type
接口也不是常常使用,通常在反射时可能会用到它,所以也非常容易忘掉,所以这次写一篇文章来简略记录下我遇到过的一些重要的完成 Type
接口的类。
我这儿先给一份我自己测验用的代码:
public class Main {
void test0() {
}
String test1() {
return "Hello, World.";
}
List<?> test2() {
ArrayList<String> l = new ArrayList<String>();
l.add("Hello, World.");
return l;
}
List<String> test3() {
ArrayList<String> l = new ArrayList<String>();
l.add("Hello, World.");
return l;
}
<T> List<T> test4(T t) {
ArrayList<T> l = new ArrayList<>();
l.add(t);
return l;
}
<T> T test5(T t) {
return t;
}
String[] test6() {
String[] strings = new String[1];
strings[0] = "Hello, World.";
return strings;
}
<T> T[] test7(T t, Class<T> clazz) {
ArrayList<T> l = new ArrayList<>();
l.add(t);
return (T[]) l.toArray();
}
void printTestReturnType() {
Class<?> clazz = Main.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method m: methods) {
String methodName = m.getName();
if (methodName.startsWith("test")) {
System.out.printf("Method -> %sn", m.toString());
Type returnType = m.getReturnType();
System.out.printf(" ReturnType: %s, TypeImplClass: %sn", returnType.getTypeName(), returnType.getClass().getName());
Type genericReturnType = m.getGenericReturnType();
System.out.printf(" GenericReturnType: %s, TypeImplClass: %sn", genericReturnType.getTypeName(), genericReturnType.getClass().getName());
if (genericReturnType instanceof ParameterizedType) {
Type[] paramsTypes = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type pt: paramsTypes) {
System.out.printf(" ParamType: %s, TypeImplClass: %sn", pt.getTypeName(), pt.getClass().getName());
}
}
if (genericReturnType instanceof TypeVariable) {
String typeVariableName = ((TypeVariable<?>) genericReturnType).getName();
System.out.printf(" TypeVariableName: %sn", typeVariableName);
}
if (genericReturnType instanceof GenericArrayType) {
Type genericType = ((GenericArrayType) genericReturnType).getGenericComponentType();
System.out.printf(" GenericComponentType: %s, TypeImplClass: %sn", genericType.getTypeName(), genericType.getClass().getName());
}
System.out.println();
}
}
}
public static void main(String[] args) {
Main m = new Main();
m.printTestReturnType();
}
}
我使用了上面的 Main
目标中的多个 test
最初的办法的回来值来测验。
Class
Class
目标是用来描述一切 Java
中的类信息,在类第一次使用时就会被加载到办法区中,后续再加载就用之前现已加载好的 Class
信息。
回到我自己写的 Demo
中,经过 Method#getReturnType()
办法就可以获取到对应回来目标的 Class
目标。假如回来目标是带泛型的目标,它的具体的泛型 Type
信息也会被抹除掉,这么说也有点怪怪的,因为 Class
目标中本来就没有具体的泛型 Type
信息(比如说 ArrayList<String>
这个复合类型,经过 ArrayList
的 Class
目标拿到的泛型信息便是一个简略的 E
,E
其实便是一个占位符,而有的 Type
获取到的泛型信息就可以是 String
,后边会讲到);假如是回来目标是一个泛型,那么拿到的便是 Object
类的 Class
目标,这便是所谓的泛型擦除;假如没有回来值,那么便是 void
的 Class
目标。
我就经过我自己写的 Demo
打印的日志来看看不同的办法回来类型回来的 Class
目标。
void test0()
ReturnType: void, TypeImplClass: java.lang.Class
String test1()
ReturnType: java.lang.String, TypeImplClass: java.lang.Class
List<String> test3()
ReturnType: java.util.List, TypeImplClass: java.lang.Class
这儿咱们看到范型 String
也是没有的哦,只要一个 List
的 Class
目标。
<T> List<T> test4(T t)
ReturnType: java.util.List, TypeImplClass: java.lang.Class
这儿我定了一个泛型 T
,回来值是一个复合类型 List<T>
,这儿看到和 List<String>
没有区别。
<T> T test5(T t)
ReturnType: java.lang.Object, TypeImplClass: java.lang.Class
这儿看到一般的泛型的对应的 Class
目标便是 Object
的 Class
目标。
String[] test6()
ReturnType: java.lang.String[], TypeImplClass: java.lang.Class
上面便是一般的目标数组对应的 Class
目标。
ParameterizedType
经过 Method#getReturnType()
得到的是一个 Class
目标,其间没有运行时具体的泛型信息。经过 Method#getGenericReturnType()
办法就可以获取到包括具体泛型信息的 Type
,这儿就不是固定的 Class
目标了,其间 ParameterizedType
目标便是一个非常常见的复合类型的 Type
,经过它的 ParameterizedType#getActualTypeArguments()
办法就可以获取到其泛型的 Type
。
我以 List<String> test3()
办法来测验看看对应的日志:
Method -> java.util.List com.tans.test.Main.test3()
ReturnType: java.util.List, TypeImplClass: java.lang.Class
GenericReturnType: java.util.List<java.lang.String>, TypeImplClass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
ParamType: java.lang.String, TypeImplClass: java.lang.Class
咱们看到回来的 Type
的完成类是 ParameterizedTypeImpl
,它完成了 ParameterizedType
接口,咱们看到它的名字是 java.util.List<java.lang.String>
,其间就有泛型的信息了,然后去拿它的具体泛型的参数,就得到了 String
的 Class
目标。
TypeVariable
描述一般泛型的 Type
,TypeVariable
中还有泛型的上界与下界的信息。经过 TypeVariable#getName()
办法可以拿到泛型的名字。
我以 <T> T test5(T t)
办法来看看测验的日志:
Method -> java.lang.Object com.tans.test.Main.test5(java.lang.Object)
ReturnType: java.lang.Object, TypeImplClass: java.lang.Class
GenericReturnType: T, TypeImplClass: sun.reflect.generics.reflectiveObjects.TypeVariableImpl
TypeVariableName: T
GenericArrayType
泛型数组对应的类型,经过 GenericArrayType#getGenericComponentType()
办法可以拿到对应的泛型 Type
,这方面和 ParameterizedType
有点类似,只不过 ParameterizedType
回来的是一个 Type
的数组,而 GenericArrayType
回来的是一个固定的 Type
,这也很好理解,数组只能有一个泛型参数。
我以 <T> T[] test7(T t, Class<T> clazz)
办法来看看测验日志:
Method -> java.lang.Object[] com.tans.test.Main.test7(java.lang.Object,java.lang.Class)
ReturnType: java.lang.Object[], TypeImplClass: java.lang.Class
GenericReturnType: T[], TypeImplClass: sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
GenericComponentType: T, TypeImplClass: sun.reflect.generics.reflectiveObjects.TypeVariableImpl
WildcardType
假如有一个复合类型 List<?>
,其间那个 ?
对应的类型便是 WildcardType
,所以经过 Method#getGenericReturnType()
永远不会回来这种类型。emm,怎么翻译这种类型呢?便是不知道什么类型的泛型吧。
我以 List<?> test2()
办法来看看测验日志(留意是从 ParameterizedType
拿出来的参数类型):
Method -> java.util.List com.tans.test.Main.test2()
ReturnType: java.util.List, TypeImplClass: java.lang.Class
GenericReturnType: java.util.List<?>, TypeImplClass: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
ParamType: ?, TypeImplClass: sun.reflect.generics.reflectiveObjects.WildcardTypeImpl
最后
期望读了本篇文章后对反射中的 Type
目标会有多一点点的认识,经过 Type
目标可以在反射的时分可以完成更多的有趣的功能。