Android、Java泛型扫盲
首先我们定义A、B、C、D四个类,他们的关系如下
1  | class A {}  | 
不指明泛型类型
1  | //以下代码均编译通过  | 
这个好理解,因为所有的类都继承与Object,故能往list里面添加任意实例对象
无边界通配符 ?
首先我们要明白一个概念,通配符?意义就是它是一个未知的符号,可以是代表任意的类。
1  | //我们发现,这样写编译不通过,原因很简单,泛型不匹配,虽然B继承A  | 
知识点
- 无边界通配符 
?能取不能存。这个好理解,因为编译器不知道?具体是啥类型,故不能存;但是任意类型都继承于Object,故能取,但取出默认为Object对象。 
上边界符 ?extends
继续上代码
1  | List<? extends C> listC;  | 
知识点
- 上边界符 
? extends只是限定了赋值给它的实例类型(这里为赋值给listC的实例类型),且边界包括自身。 - 上边界符 
? extends跟?一样能取不能存,道理是一样的,虽然限定了上边界,但编译器依然不知道?是啥类型,故不能存;但是限定了上边界,故取出来的对象类型默认为上边界的类型 
下边界符 ?super
1  | List<? super B> listB;  | 
知识点
- 下边界符 
?super,跟上边界符一样,只是限定了赋值给它的实例类型,也包括边界自身 - 下边界符 
?super能存能取,因为设定了下边界,故我们能存下边界以下的类型,当然也包括边界自身;然而取得时候编译器依然不知道?具体是什么类型,故取出默认为Object类型。 
类型擦除
首先我们要明白一点:Java 的泛型在编译期有效,在运行期会被删除 我们来看一段代码
1  | //这两个方法写在同一个类里  | 
上面的代码会有问题吗?显然是有的,编译器报错,提示如下信息: list(List<A>) clashed with list(List<B>) ; both methods have same erasure 翻译过来就是,在类型擦除后,两个方法具有相同的签名,我们来看看类型擦除后是什么样子
1  | public void list(List listA) {}  | 
可以看出,两个方法签名完全一致,故编译不通过。 明白了类型擦除,我们还需要明白一个概念
- 泛型类并没有自己独有的Class类对象
 
比如并不存在List.class或是List.class,而只有List.class 接下来这个案例就好理解了
1  | List<A> listA = new ArrayList<A>();  | 
泛型传递
现实开发中,我们经常会用到泛型传递,例如我们经常需要对Http请求返回的结果做反序列化操作
1  | public static <T> T fromJson(String result, Class<T> type) {  | 
此时我们传进去是什么类型,就会返回自动该类型的对象
1  | String result="xxx";  | 
那如果我们想返回一个集合呢,如List<A>,下面这样明显是不对的。
1  | //编译报错,前面类型擦除时,我们讲过,不存List<A>.class这种类型  | 
那我们该怎么做呢?首先,我们对fromJson改造一下,如下:
1  | //type为一个数组类型  | 
这个时候我们就可以这么做了
1  | String result="xxx";  | 
ok,我在再来,相信大多数Http接口返回的数据格式是这样的:
1  | public class Response<T> {  | 
那这种我们又该如何传递呢?显然用前面的两个fromJson方法都行不通,我们再来改造一下,如下:
1  | //这里我们直接传递一个Type类型  | 
这个Type是什么鬼?点进去看看
1  | public interface Type {  | 
哦,原来就是一个接口,并且只有一个方法,我们再来看看它的实现类

发现有5个实现类,其中4个是接口,另外一个是Class类,我们再来看看Class类的声明
1  | public final class Class<T> implements java.io.Serializable,  | 
现在有没有明白点,现在我们重点来关注下Type接口的其中一个实现接口ParameterizedType,我们来看下它的内部代码,里面就只有3个方法
1  | public interface ParameterizedType extends Type {  | 
顾名思义,ParameterizedType 代表一个参数化类型。
这个时候我们来自定义一个类,并实现ParameterizedType接口,如下:
1  | public class ParameterizedTypeImpl implements ParameterizedType {  | 
我们再次贴出fromJson方法
1  | //这里我们直接传递一个Type类型  | 
此时我们想得到Response<T>对象,就可以这样写
1  | Response<A> responseA = fromJson(result, new ParameterizedTypeImpl(Response.class, A.class));  | 
想得到List<T>对象,也可以通过ParameterizedTypeImpl得到,如下:
1  | List<A> listA = fromJson(result, new ParameterizedTypeImpl(List.class, A.class));  | 
然而,如果我们想得到Response<List<T>>对象,又该如何得到呢? ParameterizedTypeImpl一样能够实现,如下:
1  | //第一步,创建List<T>对象对应的Type类型  | 
然后,能不能再简单一点呢?可以,我们对ParameterizedTypeImpl改造一下
1  | /**  | 
此时,我们就可以这样写
1  | //第一步,直接创建Response<List<T>>对象对应的Type类型  | 
现实开发中,我们还可能遇到这样的数据结构
1  | {  | 
此时,Response<T> 里面的泛型传List肯定是不能正常解析的,我们需要再定一个类
1  | public class PageList<T>{  | 
此时就可以这样解析数据
1  | //第一步,直接创建Response<PageList<T>>对象对应的Type类型  | 
注:ParameterizedTypeImpl get(Type... types)仅仅适用于单个泛型参数的时候,如Map等,有两个泛型参数以上的不要用此方法获取Type类型。如果需要获取Map等两个泛型参数以上的Type类型。可调用getParameterized(@NonNull Type rawType, @NonNull Type... actualTypeArguments)构造方法获取,如:
1  | //获取 Map<String,String> 对应的Type类型  | 
到这,泛型相关知识点讲解完毕,如有疑问,请留言。