一、前言
- 泛化:可以用T代表任意类型,所以许多重要的类,比如集合框架,都已经成为泛型化的了,这带来了很多好处。
- 类型安全:使用 泛型 可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果不用泛型,则必须使用强制类型转换,而强制类型转换不安全,在运行期可能发生ClassCast Exception异常,如果使用泛型,则会在编译期就能发现该错误。
- 消除强制类型转换:泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。
在Android源码当中有很多地方用到了泛型。
二、使用
2.1 Java泛型接口
把泛型定义在接口,如下:
public interface 接口名<泛型类型> { }
2.1.1 定义
使用场景:网络请求后调用接口传入某个实体类(未知),请求成功后返回该实例。如下:
public interface HttpResponse<T> { //请求成功 void onSuccess(T bean); //请求失败 void onError(String response); }
2.1.2 使用
//HomeBean.class new HttpResponse<HomeBean>() { ... }; //BannerBean.class new HttpResponse<BannerBean>() { .... };
这个T可以是HomeBean
也可以是BannerBean
。
2.2 Java泛型类
把泛型定义在类上,如下:
public class 类名<泛型类型> { }
2.2.1 定义
使用场景:我们用到的地方就更多了。如网络请求返回的data(经常被定义为泛型),如下:
public class ResponseData<T> { private int errorCode; private String errorMsg; private T data; }
2.2.2使用
@GET("banner/json") Call<ResponseData<List<HomeBanner>>> homeBannerRetrofit(); @POST("user/register") @FormUrlEncoded Call<ResponseData<RegisterData>> registerRetrofit(@FieldMap Map<String,String> map);
这个T可以是List<HomeBanner>
也可以是RegisterData
。
2.3 Java泛型方法
把泛型定义在类上,如下:
public <泛型类型> 返回类型 方法名<泛型类型 变量名> { }
2.3.1 定义
使用场景:我们用到的地方就更多了。如网络请求返回的data(经常被定义为泛型),如下:
public class Test { public <T>T name(T data){ return data; }; }
2.3.2 使用
Test test = new Test(); HomeBean homeBean = test.name(new HomeBean()); RegisterData registerData = test.name(new RegisterData());
这个T可以是HomeBean
也可以是RegisterData
。
2.4 Java泛型擦除及其相关内容
在编译期间,所有泛型信息都会被擦除掉,在生成的字节码中是不包括泛型中的类型信息的。
2.4.1 ArrayList源码
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { }
这明显就是个泛型类。下面咱们看一组实例:
List<String> list = new ArrayList<>(); list.add("abc"); List<Integer> list1 = new ArrayList<>(); list1.add(123); List<UserBean> list2 = new ArrayList<>(); list2.add(new UserBean(20,"sc")); MLog.e(String.valueOf(list.getClass())); MLog.e(String.valueOf(list.getClass() == list1.getClass())); MLog.e(String.valueOf(list.getClass() == list2.getClass())); MLog.e(String.valueOf(list1.getClass() == list2.getClass()));
打印结果:
E/---mlog----: class java.util.ArrayList E/---mlog----: true E/---mlog----: true E/---mlog----: true
然后你会发现ArrayList<E>中的泛型<E>被擦除。所以add的时候全部以Object的形式添加。
2.5 Java泛型通配符
2.5.1 T,E,K,V
约定俗成的东西:
- T (type) 表示具体的一个java类型
- K V (key value) 分别代表java键值中的Key Value
- E (element) 代表Element
也可以定义为其他字母,但是不推荐,比较你用这几个别人一看就知道什么意思。
2.5.2 <? extends T>
上界通配符
上界通配符:<? extends T>
表示的是类型的上限就是自身,因此通配的参数化类型可能是T或T的子类。
代码如下:
private void test(){ // List<? extends YeYe> listZuZong = new ArrayList<ZuZong>();//报错 List<? extends YeYe> listYeYe = new ArrayList<YeYe>(); List<? extends YeYe> listBaBa = new ArrayList<BaBa>(); List<? extends YeYe> listSuSu = new ArrayList<SuSu>(); List<? extends YeYe> listZiji = new ArrayList<Ziji>(); }; class ZuZong{ } class YeYe extends ZuZong{ } class BaBa extends YeYe{ } class SuSu extends YeYe{ } class Ziji extends BaBa{ }
2.5.3 <? super T>
上界通配符
下界通配符:<? super T>
表示的是类型的下限就是自身,因此通配的参数化类型可能是T或T的父类,一直朝上直到Object。
代码如下:
List<? super YeYe> listObject = new ArrayList<Object>(); List<? super YeYe> listZuZong = new ArrayList<ZuZong>(); List<? super YeYe> listYeYe = new ArrayList<YeYe>(); // List<? super YeYe> listBaBa = new ArrayList<BaBa>();//报错 // List<? super YeYe> listSuSu = new ArrayList<SuSu>();//报错 // List<? super YeYe> listZiji = new ArrayList<Ziji>();//报错
2.5.4 <?>
无界通配符
无界通配符:任意类型。
代码如下:
List<?> listObject = new ArrayList<Object>(); List<?> listZuZong = new ArrayList<ZuZong>(); List<?> listYeYe = new ArrayList<YeYe>(); List<?> listBaBa = new ArrayList<BaBa>(); List<?> listSuSu = new ArrayList<SuSu>(); List<?> listZiji = new ArrayList<Ziji>();