注: 应该叫java 泛型
一、什么叫泛型
-----百度百科
简单来说就是将参数的类型 也可以在使用的时候变化,不同的情况下使用不同的参数类型,这就好比你用榨汁机榨汁,当你放入西瓜的时候出来的是西瓜汁,放入葡萄的时候出来的是葡萄汁。过程都是一样的---先压碎,然后将汁倒入杯子中,虽然传过来的参数类型不同
二、为什么要使用泛型
1 确定传入的参数类型
比如你向一个ArrayList集合中 添加了数字 和字符串,那么当你遍历这个集合的时候就会报错,所以一开始的时候就声明参数的类型
2 复用代码
还是集合类,如果不用泛型,那么你就要根据每个类型来判断处理逻辑甚至是一个类型一个处理类.但是,集合类,整体逻辑是一样的,就是对元素进行遍历,操作。
List<String> stringList = new ArrayList<>();
stringList.add("黄土高坡");
stringList.add("青藏高原");
stringList.add("华北平原");
List<Integer> yearList = new ArrayList<>();
yearList.add(2020);
yearList.add(2021);
再或者 返回给前端的结果就可以使用泛型进行封装
package com.example.demo.vo;
import com.example.demo.enums.CodeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author zhangyang
* @version 1.0
* @Date 2021/10/16 19:04
* @Description 结果返回类
*/
@Data
public class ResultVo<T> {
@ApiModelProperty(value = "返回码")
private String code;
@ApiModelProperty(value = "返回的信息")
private String msg;
@ApiModelProperty(value = "返回的数据")
private T data;
public static <T> ResultVo<T> success() {
return build(CodeEnum.SUCCESS);
}
public static <T> ResultVo<T> success(T data) {
return build(CodeEnum.SUCCESS, data);
}
public static <T> ResultVo<T> fail() {
return build(CodeEnum.FAIl);
}
public static <T> ResultVo<T> failed(String code, String msg) {
ResultVo<T> resultVo = new ResultVo<>();
resultVo.setCode(code);
resultVo.setMsg(msg);
return resultVo;
}
public static <T> ResultVo<T> build(String code, String msg, T data) {
ResultVo<T> resultVo = new ResultVo<>();
resultVo.setMsg(msg);
resultVo.setCode(code);
resultVo.setData(data);
return resultVo;
}
public static <T> ResultVo<T> build(String code, String msg) {
ResultVo<T> resultVo = new ResultVo<>();
resultVo.setCode(code);
resultVo.setMsg(msg);
return resultVo;
}
public static <T> ResultVo<T> build(CodeEnum codeEnum) {
return build(codeEnum, null);
}
public static <T> ResultVo<T> build(CodeEnum codeEnum, T data) {
ResultVo<T> resultVo = new ResultVo<>();
resultVo.setCode(codeEnum.getCode());
resultVo.setData(data);
resultVo.setMsg(codeEnum.getMsg());
return resultVo;
}
}
使用 :
@RestController
public class TestController {
@Autowired
UserInfo userInfo;
@GetMapping("/test")
public ResultVo<List<String>> test() {
List<String> stringList = new ArrayList<>();
stringList.add("黄土高坡");
stringList.add("青藏高原");
stringList.add("华北平原");
List<Integer> yearList = new ArrayList<>();
yearList.add(2020);
yearList.add(2021);
ResultVo<List<String>> resultVo = ResultVo.success(stringList);
return resultVo;
}
}
结果:
三 、泛型的种类与使用规则
(<> 这里面只是一个类型声明,声明了将要用到的类型)
1、泛型类
public 类名 <类型标识,一般为T> {
权限访问符 类型标识符 变量名称;
权限访问符 类型标识符 方法名(参数,可以是T修饰的,也可以是普通类型) {
}
}
比如:
public class ResultVo<T> {
public T data;
public T getData() {
return this.data;
}
}
注意:泛型类目的是为了规范其内部的数据,使这个类能够重用。但是如果你不传入泛型,也一样可以用,不过这样就失去了泛型的意义。比如
List testList =new ArrayList();
testList.add("12313");
testList.add(123);
idea都会提示你使用泛型
2 、泛型接口
public interface Generatic<T> {
T doSomeThing(T content);
}
当类实现这个泛型接口的时候也要声明类型
public class GeneraticImpl<T> implements Generatic<T> {
private T data;
@Override
public T doSomeThing(T content) {
return content;
}
}
使用:
Generatic<String> generatic = new GeneraticImpl<>();
System.out.println(generatic.doSomeThing("12313"));
3 、泛型方法
泛型方法,可以不在泛型类中使用,也可以在普通类中使用。记住<T>就是声明了一个类型,
泛型方法就是一个声明了泛型变量的方法
比如这里,泛型类声明了一个类型T,然后泛型方法声明了一个类型E,这里的E可以是任意的符号,也可以是T。
public class ResultVo<T> {
private T data;
private static <E> E build2(E data) {
return data;
}
}
public class ResultVo<T> {
private T data;
// 这里T 与类上T 两者不相同
private <T> T build2(T data) {
return data;
}
}
ResultVo<String> resultVo1 = new ResultVo<>();
resultVo1.setMsg("1111");
resultVo.testGeneric(111);
比较:
public class ResultVo<T> {
/**
* 泛型方法
* @param data
* @param <E>
* @return
*/
public <E> E testGeneric(E data) {
return data;
}
/**
* 这只是一个普通的方法,返回的是在类声明的泛型数据
* @return
*/
public T getData() {
return data;
}
}
对于静态方法的处理:
由于静态方法是跟着类走的,静态方法无法访问类上定义的泛型。所以当静态方法需要使用泛型的时候需要定义成泛型方法:
private static <T> ResultVo<T> build(CodeEnum codeEnum, T data) {
System.out.println();
ResultVo<T> resultVo = new ResultVo<>();
resultVo.setCode(codeEnum.getCode());
resultVo.setData(data);
resultVo.setMsg(codeEnum.getMsg());
return resultVo;
}
4 、通配符
当你不清楚所要传入的数据的类型的范围时,可以使用通配符?,?和Number String 等被看成是一个实际的类型,你可以把它看成所有类型的父类,就像List<String> 变成了List<?>。不过只能使用Object方法,如果需要使用其他具体类型的函数,则需要进行判断然后强转。
5 限制泛型的范围
当我们知道泛型的需要被限制在哪些范围时,就可以使用
// 使用的类型必须是Number的子类,也就是数字
public class Generic<T extends Number> {
private T data;
}
使用:
// 报错 Type parameter 'java.lang.String' is not within its bound; should extend 'java.lang.Number
Generic<String> generic =new Generic<String>();
// 正常
Generic<Integer> genericInteger =new Generic<Integer>();
---看见了一个大神写的泛型
public static <T extends Comparable<? super T>> T max (
List<? extends T>list)
)
最后记住 :当这个类所记录的数据处理方式相同的时候,就可以使用泛型(所以C++称之为模板)