泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。利用好泛型,在系统架构中是一把利器。
泛型类
先看一个例子,restful架构中,需要定义api接口返回结构,定义如下:
package com.company.project.core;
import com.alibaba.fastjson.JSON;
/**
* 统一API响应结果封装
*/
public class Result {
private int code;
private String message;
private Object data;
public Result setCode(ResultCode resultCode) {
this.code = resultCode.code;
return this;
}
public int getCode() {
return code;
}
public Result setCode(int code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public Result setMessage(String message) {
this.message = message;
return this;
}
public Object getData() {
return data;
}
public Result setData(Object data) {
this.data = data;
return this;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
这是最常见的做法,这样做的一个坏处是消息体data的元素我们不知道是什么类型,需要强制转换,另外如果用swagger的话,在线文档解析不出data具体的字段内容,api接口使用者不知道应该怎么解决这个data对象,使用泛型可以很好的解决这个问题。
package cn.watchvip.mall.common.core;
import com.alibaba.fastjson.JSON;
/**
* 统一API响应结果封装
*/
public class Result {
private int code;
private String msg;
private T data;
public Result setCode(ResultCode resultCode) {
this.code = resultCode.code;
return this;
}
public int getCode() {
return code;
}
public Result setCode(int code) {
this.code = code;
return this;
}
public String getMsg() {
return msg;
}
public Result setMsg(String msg) {
this.msg = msg;
return this;
}
public T getData() {
return data;
}
public Result setData(T data) {
this.data = data;
return this;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
泛型方法
泛型方法只需要在方法签名的返回值前加一个类似
获取一个空集合:
public static final List emptyList() {
return (List) EMPTY_LIST;
}
获取一个空Map
public static final Map emptyMap() {
return (Map) EMPTY_MAP;
}
这样就可以获取任何类型的空集合了,如下:
List emptyList = Collections.emptyList();
Map emptyMap = Collections.emptyMap();
边界符 >
掌握了泛型类与泛型方法基本能满足大部分开发中的需要了,但还远不够,考虑这样一个需求,查找一个泛型数组中大于某个特定元素的个数,我们可以通过泛型方法这样实现:
public static int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
但是这样很明显是错误的,因为除了short, int, double, long, float, byte, char等原始类型,其他的类并不一定能使用操作符>,所以编译器报错,那怎么解决这个问题呢?答案是使用边界符。
public interface Comparable {
public int compareTo(T o);
}
做一个类似于下面这样的声明,这样就等于告诉编译器类型参数T代表的都是实现了Comparable接口的类,这样等于告诉编译器它们都至少实现了compareTo方法。
public static > int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
通配符 extends T>
不能往里存,只能往外取
在讨论通配符之前,我们设想一下如果我们考虑实现一个可以对int,flow,bouble类型都可以进行做加法的方法,我想90%的人都会写出以下方法
public static void add(Collection c){
}
public static void main(String[] args) {
List integers = Arrays.asList(1, 2, 3);
List doubles = Arrays.asList(1.1, 2.1);
add(integers);//不允许
add(doubles);//不允许
}
众所周知,java是可以向上转型的,这也是我们面向接口编程的基础,如下:
List list = new ArrayList();
list = new LinkedList<>();
但泛型却是不支持向上转的,
List list = new ArrayList(); //编译不通过
虽然Integer是Number的子类,但在泛型中,两个是完全没有关系的。
add方法中的参数Collection
public static void add(Collection extends Number> c){
}
public static void main(String[] args) {
List integers = Arrays.asList(1, 2, 3);
List doubles = Arrays.asList(1.1, 2.1);
add(integers);
add(doubles);
}
通配符
只能往里存,不能往外取
其它
List,List