java中泛型的使用(开发中很常见),通俗易懂!

一.什么是泛型

  • 泛型是一种未知的数据类型,当我们不知道使用什么数据类型是,可以使用泛型

  • 泛型可以看成一个变量,用来接收数据类型

    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
}
总结

这样一来,无论登录成功还是失败,我们统一了返回的数据的格式,从而方便前端处理, 也规范了我们的代码

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值