Java 泛型之认识泛型,泛型方法,泛型类,泛型接口和通配符

 2022-09-18
原文地址:https://cloud.tencent.com/developer/article/1907341

泛型

什么是泛型:

泛型就相当于标签

形式:<>

jdk1.5之后,用泛型来解决元素类型不确定的数据保存操作,

例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。

没有泛型的集合

        public static void main(String[] args) {
            ArrayList al = new ArrayList();
            al.add(98);
            al.add(18);
            al.add(38);
            al.add(88);
            al.add("丽丽");
            for (Object o : al) {
                System.out.print(o+" ");
            }
        }

如果不使用泛型的话,有缺点:

一般我们在使用的时候基本上往集合里随意放值,因为底层是一个obj类型的数组,所以什么都能放,不方便管理。

在jdk1.5以后开始,使用泛型加入泛型的优点:在编译的时候就会对类型进行检查,不是泛型的就无法添加到这个集合

        public static void main(String[] args) {
            ArrayList<Integer> al = new ArrayList();
            al.add(98);
            al.add(18);
            al.add(38);
            al.add(88);
            for (Integer o : al) {
                System.out.print(o+" ");
            }
        }

总结:

  1. JDK1.5之后
  2. 泛型实际就是一个<>引起来的参数类型,这个参数类型具体在使用的时候才会确定类型

202209182102534571.png

  1. 使用了泛型后,可以确定集合的类型,在编译的时候就可以检查出来
  2. 使用泛型可能觉得麻烦,实际上使用泛型才会简单,后续的便利操作会简单许多
  3. 泛型对应的类型都是引用类型不能是基本类型

泛型类和泛型接口

声明泛型类时传入类型实参 创建泛型类对象时,传入类型实参 类型实参为空时,默认为Object类型

继承泛型类:

1.泛型父类不传入类型实参,默认为Object类型 2.泛型父类传入类型实参,子类既可以是泛型类,也可以不是 3.泛型父类传入类型实参,则子类必须是泛型类,且子类的类型形参列表必须包含父类的类型形参列表

泛型类的定义和实例化,如果实例化的时候不明确指定泛型,那么默认为Object类型

    package TestGeneric.GenericTest;
    
    
    public class test01<e> {
    /*
    * 这是一个普通类
    * test01就是一个泛型类
    * <>里面就是一个参数类型,但是这个类型是什么?,不确定,相当于一个占位
    * 但是现在确定的是这个类型一定是引用类型,而不是基本类型
    * */
    int age;
    String name;
    e sex;
    public void a(e n){
    
    }
    public void b(e[] n){
    
    }
    static class Test{
        public static void main(String[] args) {
        test01 gt1 = new test01();
        gt1.a("abc");
        gt1.a(17);
        gt1.a(9.8);
        gt1.b(new String[]{"a","b","A"});
    
            test01<String> gt2 = new test01<>();
            gt2.sex ="男";
            gt2.a("abc");
            gt2.b(new String[]{"a","b","A"});
        }
    
    }
    }
继承:父类指定泛型接口

当父类指定了泛型类型,子类就不许要再指定了,可以直接使用

    static class SubGeneric extends test01<Integer>{
    
    }
    
    static class Demo{
        public static void main(String[] args) {
                SubGeneric sgt = new SubGeneric();
                    sgt.a(19);
        }
    }
继承:父类不指定

如果父类不指定泛型,那么子类在实例化的时候需要指定

        static class SubGeneric2<e> extends test01<e>{
                
        }

泛型类可以定义多个参数类型

202209182102571042.png

泛型类的构造器写法:

202209182102579603.png

不同泛型的引用类型不可以互相赋值

202209182102589664.png

泛型如果不指定,就会被擦除,例子就是

202209182102599215.png

泛型类中的静态方法不能使用类的泛型

202209182103022546.png

不能直接使用泛型数组的创建,如果非要创建

202209182103034557.png

泛型方法

  1. 什么是泛型方法,不是带泛型的方法就是泛型方法,泛型方法有要求:这个方法的泛型参数类型要和当前类的泛型方法的泛型无关
  2. 换个角度:泛型方法对应的那个泛型参数类型和当前所在的这个类,是否为泛型类,泛型是啥,无关
  3. 泛型方法定义的时候,前面要加上t,原因如果不加的话,会把t当作一种数据类型,然而代码中没有t类型那么就会报错
  4. t的类型实在调用方法的时候确定的
  5. 泛型方法是否是静态方法?可以是

代码类型:

    public class test02<e> {
        public  void a(e e){
    
        }
        public static <T>  void b(T t){
    
        }
    
    static class Demo{
        public static void main(String[] args) {
            test02<String> t2 = new test02();
            t2.a("1");
            t2.b("abc");
        }
    }

泛型参数存在继承的情况

前面两个引用类型,都可以赋值,为什么list不行?

其实我们用的Arraylist,他的底层是一个Obj类型的数组,我们的泛型负责在编译的时候限制类型,

例子:两个类,a,b两类,a是b的父类,两者是继承关系,但是 G ,G 两者不存在继承关系,应为他们都是引用Arraylist所以是同级关系

202209182103050218.png

通配符

当我想要重载不同泛型的list时,常见的重载无法让我们完成需求,于是我们需要通配符

在没有通配符的情况下,下面a方法,相当于重复定义

202209182103069069.png

通配符是什么?

2022091821030784910.png

发现:两个类,a,b两类,a是b的父类,两者是继承关系,但是 G< a> ,G< b>两者不存在继承关系,应为他们都是引用Arraylist所以是同级关系但是使用了通配符后,我们发现G变成了G< a> ,G< b>的父类

使用通配符

无边界通配符( ?),固定上边界通配符(?extends 上界类),固定下边界通配符(?super 下界类)

学习主要就是为了方便查看API文档

2022091821030931911.png

使用小细节

    public  void  a(List<?> list){
    //    遍历
        for (Object o : list) {
            System.out.println(o);
        }
    
    //    数据的写入操作
    //    list.add("abc");--》出错,不能随意的写入
    
    //    读取操作
        Object s  = list.get(0);
    }

泛型受限

并列关系,我们如何限制类型,

  • 用extends的是本类和类所有的子类:定义上限
  • 用super是本类和本类的父类,定义下限

2022091821031109812.png

            List<Object> a = new ArrayList<>();
            List<Person> b = new ArrayList<>();
            List<Student> c = new ArrayList<>();

A,B,C三个泛型的类型不相同,Person是Student的父类