为何要写这一系列的博客呢?java
由于在 Android 开发的过程当中, 泛型,反射,注解这些知识进场会用到,几乎全部的框架至少都会用到上面的一两种知识,如 Gson 就用到泛型,反射,注解,Retrofit 也用到泛型,反射,注解 。学好这些知识对咱们进阶很是重要,尤为是阅读开源框架源码或者本身开发开源框架。程序员
注解使用入门(一)bash
错误可分为两种:编译时错误与运行时错误。编译时错误在编译时能够发现并排除,而运行时错误具备很大的不肯定性,在程序运行时才能发现,形成的后果多是灾难性的。测试
泛型的引入使得一部分错误能够提早到编译时期发现,极大地加强了代码的健壮性。可是咱们知道 java 泛型在运行的时候是会进行泛型擦除的,那咱们要怎样获得在编译时期泛型的信息呢?java 为咱们提供了 Type 接口,使用它,咱们能够获得这些信息。ui
不知道什么是泛型擦除的同窗能够看一下
类型擦除是指泛型在运行的时候会去除泛型的类型信息。java 中,泛型主要是在编译层次来实现的,在生成的字节码即 class 文件是不包括泛型的 类型信息的。 即 List, List ,List 虽然在编译时候是不一样的,可是在编译完成后,在class 文件 中都只会把他们看成 List 来对待。
简单来讲:Type是全部类型的父接口, 如原始类型(raw types 对应 Class)、 参数化类型(parameterized types 对应 ParameterizedType)、 数组类型(array types 对应 GenericArrayType)、 类型变量(type variables 对应 TypeVariable )和基本(原生)类型(primitive types 对应 Class),。
子接口有 ParameterizedType, TypeVariable, GenericArrayType, WildcardType, 实现类有Class。
官方文档的说明是这样的
ParameterizedType represents a parameterized type such as Collection
须要注意的是,并不仅是 Collection 才是 parameterized,任何相似于 ClassName 这样的类型都是 ParameterizedType ,好比下面的这些都是 parameterizedType.
Map<String, Person> map;
Set<String> set1;
Class<?> clz;
Holder<String> holder;
List<String> list;
static class Holder<V>{
}
复制代码
而相似于这样的 ClassName 不是 ParameterizedType.
Set set;
List aList;
复制代码
Type[] getActualTypeArguments(); 返回 这个 Type 类型的参数的实际类型数组。 如 Map<String,Person> map 这个 ParameterizedType 返回的是 String 类,Person 类的全限定类名的 Type Array。
Type getRawType() 返回的是当前这个 ParameterizedType 的类型。 如 Map<String,Person> map 这个 ParameterizedType 返回的是 Map 类的全限定类名的 Type Array。
Type getOwnerType();
Returns a {@code Type} object representing the type that this type is a member of.
这个比较少用到。返回的是这个 ParameterizedType 所在的类的 Type (注意当前的 ParameterizedType 必须属于所在类的 member)。解释起来有点别扭,仍是直接用代码说明吧。 好比 Map<String,Person> map 这个 ParameterizedType 的 getOwnerType() 为 null,而 Map.Entry<String, String>entry 的 getOwnerType() 为 Map 所属于的 Type。
说了这么多,下面咱们一块儿来看一下例子,加深印象。
public class ParameterizedTypeBean {
// 下面的 field 的 Type 属于 ParameterizedType
Map<String, Person> map;
Set<String> set1;
Class<?> clz;
Holder<String> holder;
List<String> list;
// Map<String,Person> map 这个 ParameterizedType 的 getOwnerType() 为 null,
// 而 Map.Entry<String, String> entry 的 getOwnerType() 为 Map 所属于的 Type。
Map.Entry<String, String> entry;
// 下面的 field 的 Type 不属于ParameterizedType
String str;
Integer i;
Set set;
List aList;
static class Holder<V> {
}
}
复制代码
public class TestHelper {
public static void testParameterizedType() {
Field f = null;
try {
Field[] fields = ParameterizedTypeBean.class.getDeclaredFields();
// 打印出全部的 Field 的 TYpe 是否属于 ParameterizedType
for (int i = 0; i < fields.length; i++) {
f = fields[i];
PrintUtils.print(f.getName()
+ " getGenericType() instanceof ParameterizedType "
+ (f.getGenericType() instanceof ParameterizedType));
}
getParameterizedTypeMes("map" );
getParameterizedTypeMes("entry" );
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void getParameterizedTypeMes(String fieldName) throws NoSuchFieldException {
Field f;
f = ParameterizedTypeBean.class.getDeclaredField(fieldName);
f.setAccessible(true);
PrintUtils.print(f.getGenericType());
boolean b=f.getGenericType() instanceof ParameterizedType;
PrintUtils.print(b);
if(b){
ParameterizedType pType = (ParameterizedType) f.getGenericType();
PrintUtils.print(pType.getRawType());
for (Type type : pType.getActualTypeArguments()) {
PrintUtils.print(type);
}
PrintUtils.print(pType.getOwnerType()); // null
}
}
}
复制代码
print:map getGenericType() instanceof ParameterizedType true
print:set1 getGenericType() instanceof ParameterizedType true
print:clz getGenericType() instanceof ParameterizedType true
print:holder getGenericType() instanceof ParameterizedType true
print:list getGenericType() instanceof ParameterizedType true
print:str getGenericType() instanceof ParameterizedType false
print:i getGenericType() instanceof ParameterizedType false
print:set getGenericType() instanceof ParameterizedType false
print:aList getGenericType() instanceof ParameterizedType false
print:entry getGenericType() instanceof ParameterizedType true
print:java.util.Map<java.lang.String, com.xujun.gennericity.Person>
print:true
print:interface java.util.Map
print:class java.lang.String
print:class com.xujun.gennericity.Person
print:null
print:java.util.Map.java.util.Map$Entry<java.lang.String, java.lang.String>
print:true
print:interface java.util.Map$Entry
print:class java.lang.String
print:class java.lang.String
print:interface java.util.Map
好比 public class TypeVariableBean<K extends InputStream & Serializable, V> ,K ,V 都是属于类型变量。
public class TypeVariableBean<K extends InputStream & Closeable, V> {
// K 的上边界是 InputStream
K key;
// 没有指定的话 ,V 的 上边界 属于 Object
V value;
// 不属于 TypeTypeVariable
V[] values;
String str;
List<K> kList;
}
复制代码
TypeVariableBean bean = new TypeVariableBean<FileInputStream, String>();
fk = TypeVariableBean.class.getDeclaredField("key");
eyType = (TypeVariable) fk.getGenericType();
System.out.println(keyType.getName());System.out.println(keyType.getGenericDeclaration());
复制代码
执行上述代码,将能够看到以下的效果
K
class com.xujun.gennericity.beans.TypeVariableBean
represents an array type whose component type is either a parameterized type or a type variable.
简单来讲就是:范型数组,组成数组的元素中有范型则实现了该接口; 它的组成元素是 ParameterizedType 或 TypeVariable 类型
// 属于 GenericArrayType
List<String>[] pTypeArray;
// 属于 GenericArrayType
T[] vTypeArray;
// 不属于 GenericArrayType
List<String> list;
// 不属于 GenericArrayType
String[] strings;
// 不属于 GenericArrayType
Person[] ints;
复制代码
下面咱们一块儿来看一下例子
public class GenericArrayTypeBean<T> {
public void test(List<String>[] pTypeArray, T[] vTypeArray,
List<String> list, String[] strings, Person[] ints) {
}
}
复制代码
public static void testGenericArrayType() {
Method method = GenericArrayTypeBean.class.getDeclaredMethods()[0];
System.out.println(method);
// public void test(List<String>[] pTypeArray, T[]
// vTypeArray,List<String> list, String[] strings, Person[] ints)
Type[] types = method.getGenericParameterTypes(); // 这是 Method 中的方法
for (Type type : types) {
System.out.println(type instanceof GenericArrayType);// 依次输出true,true,false,false,false
}
}
复制代码
输出结果
public void com.xujun.gennericity.beans.GenericArrayTypeBean.test(java.util.List[],java.lang.Object[],java.util.List,java.lang.String[],com.xujun.gennericity.Person[])
true
true
false
false
false
{@code ?}, {@code ? extends Number}, or {@code ? super Integer} 这些类型 都属于 WildcardType
extends 用来指定上边界,没有指定的话上边界默认是 Object, super 用来指定下边界,没有指定的话为 null。
几个主要方法介绍
下面一块儿来看一下例子。
public class WildcardTypeBean {
private List<? extends Number> a; // a没有下界,
// 没有指定的话,上边界默认是 Object ,下边界是 String
private List<? super String> b;
private List<String> c;
private Class<?> aClass;
}
复制代码
public static void testWildCardType() {
try {
Field[] fields = WildcardTypeBean.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Type type = field.getGenericType();
String nameString = field.getName();
PrintUtils.print("下面开始打印" + nameString + "是否具备通配符");
if (!(type instanceof ParameterizedType)) {
PrintUtils.print("---------------------------");
continue;
}
ParameterizedType parameterizedType = (ParameterizedType) type;
type = parameterizedType.getActualTypeArguments()[0];
if (!(type instanceof WildcardType)) {
PrintUtils.print("---------------------------");
continue;
}
WildcardType wildcardType = (WildcardType) type;
Type[] lowerTypes = wildcardType.getLowerBounds();
if (lowerTypes != null) {
PrintUtils.print("下边界");
PrintUtils.printTypeArr(lowerTypes);
}
Type[] upTypes = wildcardType.getUpperBounds();
if (upTypes != null) {
PrintUtils.print("上边界");
PrintUtils.printTypeArr(upTypes);
}
PrintUtils.print("---------------------------");
}
Field fieldA = WildcardTypeBean.class.getDeclaredField("a");
Field fieldB = WildcardTypeBean.class.getDeclaredField("b");
// 先拿到范型类型
PrintUtils.print(fieldA.getGenericType() instanceof ParameterizedType);
PrintUtils.print(fieldB.getGenericType() instanceof ParameterizedType);
ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
// 再从范型里拿到通配符类型
PrintUtils.print(pTypeA.getActualTypeArguments()[0] instanceof WildcardType);
PrintUtils.print(pTypeB.getActualTypeArguments()[0] instanceof WildcardType);
WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
// 方法测试
System.out.println(wTypeA.getUpperBounds()[0]);
System.out.println(wTypeB.getLowerBounds()[0]);
// 看看通配符类型究竟是什么, 打印结果为: ? extends java.lang.Number
System.out.println(wTypeA);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
复制代码
Type及其子接口的来历
没有泛型的时候,只有原始类型。此时,全部的原始类型都经过字节码文件类Class类进行抽象。Class类的一个具体对象就表明一个指定的原始类型。
泛型出现以后,扩充了数据类型。从只有原始类型扩充了参数化类型、类型变量类型、限定符类型 、泛型数组类型。
咱们知道在 jdk 1.5 之前的时候,是没有 泛型的。在 jdk 1.5 的时候,才引入了泛型。若是真的在动态运行的时候加入泛型,涉及到 JVM 命令的修改,这无疑是很是致命的。所以折中采起了这样的策略,在编译的时候进行检查,在运行的时候进行擦除,也是咱们说的泛型擦除。 同时这也说明一点,在设计框架的时候,框架的健壮性和灵活性很是重要。
咱们知道如今的框架都会使用泛型,掌握 Type 有利于咱们读懂它们的源码,或者本身动手打造框架。如 Android 的经常使用开源框架 Gson ,Retrofit等。
最近更新博客的频率有点低,主要是由于惰性吧。天天实习完之后,有点累,就不太想写博客了。我如今也不知道我能坚持到何时,顺其天然吧。PS,真的愈来愈佩服那些坚持写博客的人,大家是最棒的。
扫一扫,欢迎关注个人微信公众号 stormjun94(徐公码字), 目前是一名程序员,不只分享 Android开发相关知识,同时还分享技术人成长历程,包括我的总结,职场经验,面试经验等,但愿能让你少走一点弯路。