泛型又叫参数化类型,其主要描述的是在进行类,接口,方法的定义时,使用抽象的数据结构或者进行简单的约束,其真实装载的数据结构或对象关系由开发者在创建该类,接口,方法时实现,Android开发中最典型的泛型应用就是Gson解析后端返回数据的场景。
网络请求数据解析中的泛型
假设服务器接口定义,所有接口统一返回如下的json数据:
// data为一个JsonObject
{"code":"0","message":"success","data":{}}
// data为一个JsonArray
{"code":"0","message":"success","data":[]}
其中code代表请求的错误码,message代表接口请求信息,data代表接口返回的数据结构,那么我们可以预知到在请求多个接口时,data域中的内容也是不一样的,如果按照一般实体解析,我们每个实体类中都会有code,message这两个成员,那么有没有办法进行归一呢?这里就要用到泛型了,我们使用泛型定义上述接口返回所对应的实体如下所示:
// 泛型T代表data所对应的类型,有可能是Object,也有可能是List,具体由调用方指定
public class HttpResponse <T>{
private String code;
private String message;
private T data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Gson解析使用TypeToken来指定这里泛型T的类型以完成后段返回数据解析,代码段如下:
String responseStr = response.body().string();
// 这里的String就代表data是一个字符串,对应上述实体类中的泛型T
Type type = new TypeToken<HttpResponse<String>>(){}.getType()
HttpResponse httpResponse = new Gson().fromJson(responseStr,type);
容器类中的泛型
Java自身内部也有很多泛型声明,比如我们的各种容器类,如ArrayList,List,Collection等,Collection的定义如下所示:
public interface Collection<E> extends java.lang.Iterable<E> {
public int size();
public boolean isEmpty();
public boolean contains(@libcore.util.Nullable java.lang.Object o);
@libcore.util.NonNull public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
public java.lang.@libcore.util.Nullable Object @libcore.util.NonNull [] toArray();
public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
public boolean add(@libcore.util.NullFromTypeParam E e);
public boolean remove(@libcore.util.Nullable java.lang.Object o);
public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
public default boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
public void clear();
public boolean equals(@libcore.util.Nullable java.lang.Object o);
public int hashCode();
@libcore.util.NonNull public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
@libcore.util.NonNull public default java.util.stream.Stream<@libcore.util.NullFromTypeParam E> stream() { throw new RuntimeException("Stub!"); }
@libcore.util.NonNull public default java.util.stream.Stream<@libcore.util.NullFromTypeParam E> parallelStream() { throw new RuntimeException("Stub!"); }
}
从这里可以看出泛型类在被继承时,泛型数据是要发生传递的,A类中声明一个泛型T,B是A的字类,其最少也要声明一个泛型,以传递给A,确保A可以正常初始化。
架构设计中的泛型
在MVP的基础设计中,我们通过声明BaseView,BasePresenter,BaseModel,然后在其各自的子类中实现相对应的业务代码,形成一套代码规范,将一些公共逻辑封装在BaseXXX中。
但随着开发团队的人员更迭,代码量的增加,新同学在使用MVP时可能会只使用三个基类中的一个或两个,乃至搭配自己实现的其他BaseXXX类,导致业务逻辑异常,那么有没有办法形成约束,使得这三个绑定在一起使用呢?此时就需要用到泛型了。
以泛型搭建约束,实现的IBaseView,IBasePresenter,IBaseModel如下所示:
public interface IBaseView <T extends BasePresenter>{
}
public interface IBasePresenter <V extends BaseView,M extends BaseModel>{
}
public interface IBaseModel {
}
对应的Base实现类,BaseView,BasePresenter,BaseModel如下图所示
public class BaseView<P extends BasePresenter> implements IBaseView<MainPresenter> {
}
public class BasePresenter<V extends BaseView,M extends BaseModel> implements IBasePresenter<V,M>{
}
public class BaseModel implements IBaseModel{
}
业务实现的View,Presenter,Model如下所示:
public class MainView extends BaseView<MainPresenter>{
}
public class MainPresenter extends BasePresenter<MainView,MainModel>{
}
public class MainModel extends BaseModel {
}
从代码可以看出我们使用泛型实现了,View,Presenter,Model三者之间的持有关联依赖关系,确保其他开发者能按照我们设计的规范使用这三个类。
<?>和 < T > 有什么区别?
泛型符号 | 含义 | 备注 |
< T > | 通配特定的一种类型,在定义时,类型确定且一致,如List strList = new ArrayList(); | / |
<?> | 通配任意类型,假设ArrayList<?> arrays= new ArrayList();这种书写成立,那么代表arrays中可以装载任意类型的对象 | / |
- <?extends E>或:表示所通配的类型为E或者E的子类型
- <?super E>或:表示通配的类型为E或E的父类型