一.什么是泛型
-
泛型是一种未知的数据类型,当我们不知道使用什么数据类型是,可以使用泛型
-
泛型可以看成一个变量,用来接收数据类型
E e :Element元素
T t :Type类型
-
ArrayList集合在定义的时候不知道要使用什么类型,所以用泛型
E:未知的数据类型
public class ArrayList<E>{ public boolean add(E e){} public E get(int index){} }
注意:创建集合对象的时候,就会确定泛型的数据类型
ArrayList<String> list = new ArraLlist<String>(); //之后E就变成String ArrayList <Student> list = new ArraLlist<Student>(); //E就变成student public class ArrayList<Student>{ public boolean add(Student e){} public Student get(int index){} }
若集合不使用泛型,参数默认的类型就是Object类型,可以存储任意类型的数据,弊端:集合不安全,会引发异常
String s = (String)obj 会抛出异常,不能把Integer类型转换为String类型
- 定义含有泛型的类,在创建对象的时候确定泛型
public class A<E>{
private E name;
public E getName(){}
public void setName(E name){
this.name = name;
}
}
public static void main(){
A a = new A(); //不写泛型,默认是object类型
a.setName("i love you");
Object obj = gc.getName();
A<Integer> a = new A<>();
}
-
定义含有泛型的方法,泛型定义在方法的修饰符和返回值类型之间
class A{ public <M> void method01(M m){ sout(m); } //直接类名调用 public static <S> void method02(S s){ sout(s); } } public static void main(){ new A.method01(10); new A.method01("110"); M.method02(true); }
二.定义含有泛型的接口
-
定义含有泛型的接口
1.第一种使用接口方式:定义接口的实现类,实现接口,并指定接口的泛型
public interface Iterator<E>{ E next(); } scanner类实现了Iterator接口,并指定了接口的泛型为字符串,所以重写的next方法泛型默认就是字符串 public final class Scanner implements Iterator<String>{ public String next(){} }
-
public interface Generic<I>{ public abstract void method(I i);//接口中的方法一定是public abstract方法 } public class GenericImp implements Generic<String>{ public void method(Stirng s){ sout(s); } }
2.第二种使用接口方式:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走
就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型
比如说:
public interface List<E>{ boolean add(E e); E get(int index); } public class ArrayList<E> implements List<E>{ public boolean add(E e); E get(int index); }
public interface Generic<I>{ public abstract void method(I i);//接口中的方法一定是public abstract方法 } public class GenericImp2<I> implements Generic<I>{ public void method(I i){ sout(i); } } public static class main(String[] args){ GenericImp2<Integer> gi2 = new GenericImp2<>(); gi2.method(2); GenericImp2<Double> gi2 = new GenericImp2<>(); gi2.method(8.8); }
三.泛型通配符
? :代表任意的数据类型,不能创建对象使用,只能作为方法的参数使用
public class Fanxing {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(12);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArray(list01);
printArray(list02);
}
/*
定义一个方法,能遍历所有类型的ArrayList集合
这时候我们不知道ArrayList集合使用什么数据类型,可以使用泛型的通配符?
注意:泛型没有继承概念,因此
public static void printArray(ArrayList<Object> list)会报错
*/
public static void printArray(ArrayList<?> list){
//获取迭代器遍历集合,集合是什么类型,迭代器的泛型就是什么类型
Iterator<?> it = list.iterator();
while (it.hasNext()){
Object o = it.next();
System.out.println(o);//这里会取调用子类对象的toString方法
}
}
}
四.在开发中的应用
比如我们在返回给前端数据时,需要按照一定的json格式返回;
比如:
{
code: "0",
message: "用户名不存在",
data: null
}
code表示状态码
message表示信息
data表示要返回的数据
那此时我们需要在后端创建相应的类
@Data
public class ResultVO<T> {
private String code;
private String message;
private T data;
}
注意这里@Data是lombok提供的注解,简单来讲使用了这个注解,就可以代替你的getter,setter,构造函数,tostring一系列东西,感兴趣的朋友可以自行搜索,我后面也会写一篇有关lombok的文章
这里就使用了泛型,由于不知道我们要返回给前台的数据时什么格式的,所以这里使用泛型T来接收;具体要传入什么类型的数据,就看setdata,设置什么了,如果不设置T的类型,默认是object类型;
下面是开发中实现的登录功能的源代码,仅供参考:
@Data
public class ResultVO<T> {
private String code;
private String message;
private T data;
}
下面是一个工具类
public class ResultVOUtil {
//成功
public static ResultVO success(Object object){
ResultVO resultVO = new ResultVO();
resultVO.setCode("1");
resultVO.setMessage("成功");
resultVO.setData(object);
return resultVO;
}
public static ResultVO userNotExist(){
ResultVO resultVO = new ResultVO();
resultVO.setCode("0");
resultVO.setMessage("用户名不存在");
return resultVO;
}
public static ResultVO pwdNotTrue(){
ResultVO resultVO = new ResultVO();
resultVO.setCode("0");
resultVO.setMessage("密码错误");
return resultVO;
}
}
下面是controller代码
@PostMapping("/login")
@ResponseBody
public ResultVO checkUsernameAndPassword(@RequestParam("username") String username,
@RequestParam("password") String password){
StuLogin user = displayService.findPasswordByUsername(username);
Map<String,String> map = new HashMap<>();
if (user == null) {
return ResultVOUtil.userNotExist();
}else{
if (password.equals(user.getPassword())){
return ResultVOUtil.success(username);
}
}
return ResultVOUtil.pwdNotTrue();
}
实际效果:
登录成功:
{
code: "1",
message: "成功",
data: "mike"
}
登录失败:
{
code: "0",
message: "用户名不存在",
data: null
}
总结
这样一来,无论登录成功还是失败,我们统一了返回的数据的格式,从而方便前端处理, 也规范了我们的代码