• 76-Java的泛型深入、自定义泛型、泛型通配符、上下限


    泛型深入

    一、泛型的概述和优势

    1、概述

    • 泛型:是JDK5中引入的特性,可以在编译阶约束操作的数据类型,并进行检查。

    2、格式

    <数据类型>
    
    • 1
    • 注意:泛型仅支持引用数据类型。

    • 集合体系的全部接口和实现类都是支持泛型的使用。

      在这里插入图片描述



    3、好处、优势

    • 统一数据类型。
    • 把运行期间的问题提到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来了。
    package com.app.d7_genericity;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
        目标:理解泛型,深入体会泛型的优势
     */
    public class GenericityDemo1 {
        public static void main(String[] args) {
            // 不用泛型,当你在运行期间,会出现强制类型转换的bug
            List list1 = new ArrayList<>();
            list1.add("Java");
            list1.add("赵敏");
            list1.add(34.6);
            list1.add(false);
            list1.add(343);
            System.out.println("list1 = " + list1);
    
            /*for (Object o : list1) {
                String ele = (String) o;
                System.out.println(ele);
            }*/
    
    
            // 使用泛型,在编译期间已经确定了数据类型,后面需要对数据做处理的话,就不会出现强制类型转换这样的操作了
            // List list2 = new ArrayList<>(); // 报错!因为泛型仅支持引用数据类型
            List<Integer> list2 = new ArrayList<>();
            list2.add(343);
            list2.add(33);
            System.out.println("list2 = " + list2);
            // 报错!因为此集合需要整数类型的数据,给的却是字符串类型
            // list2.add("Java");
            // list2.add("赵敏");
    
            // 报错!因为此集合需要整数类型的数据,给的却是浮点类型
            // list2.add(34.6);
    
            // 报错!因为此集合需要整数类型的数据,给的却是布尔类型
            // list2.add(false);
    
    
            System.out.println("-----------------------------------");
            // 想使用泛型,但是又想存储任意类型的数据
            List<Object> list3 = new ArrayList<>();
            list3.add("Java");
            list3.add("赵敏");
            list3.add(34.6);
            list3.add(false);
            list3.add(343);
            System.out.println("list3 = " + list3);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    list1 = [Java, 赵敏, 34.6, false, 343]
    list2 = [343, 33]
    -----------------------------------
    list3 = [Java, 赵敏, 34.6, false, 343]
    
    Process finished with exit code 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4、泛型的用武之地

    • 类后面——>泛型类。
    • 方法申明上——>泛型方法。
    • 接口后面——>泛型接口。



    二、自定义泛型类

    1、概述

    • 定义类的同时定义了泛型的类,就是泛型类。

    2、格式

    修饰符 class 类名<泛型变量>{}
    
    • 1
    • 范例:
    public class MyArrayList<T> {
        
    }
    
    • 1
    • 2
    • 3
    • 此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等。

    3、作用

    • 编译阶段可以指定数据类型,类似于泛型在集合中的作用。

    4、案例导学

    • 模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。

      package com.app.d8_genericity_class;
      
      import java.util.ArrayList;
      
      /**
          定义泛型类
       */
      public class MyArrayList<E> {
          /**
           * 拓展:装饰模式的思想
           * 通俗点讲:
           *  我买了一片国外的芯片,装饰上我的自己的芯片外壳
           */
          private ArrayList<Object> list = new ArrayList<>();
      
          /**
           * 模拟添加功能
           * @param e     要添加的元素
           */
          public void add(E e){
              // 内部用的是国外芯片的添加方法
              list.add(e);
          }
      
          /**
           * 模拟删除功能
           * @param e     要删除的元素
           */
          public void remove(E e){
              // 内部用的是国外芯片的删除方法
              list.remove(e);
          }
      
          /**
           * 重写toString,格式化输出,不然会输出一个内存地址信息
           * @return
           */
          @Override
          public String toString() {
              // 里面返回的是国外芯片的toString
              return list.toString();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      package com.app.d8_genericity_class;
      
      /**
          目标:通过案例导学,学会定义泛型类、理解装饰模式的思想
          需求:模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。
       */
      public class Test {
          public static void main(String[] args) {
              // 创建我们自己定义的泛型类:MyArrayList集合
              MyArrayList<String> list1 = new MyArrayList<>();
              // 添加元素
              list1.add("JavaSE");
              list1.add("JavaSE");
              list1.add("我的集合");
              list1.add("我的集合");
              list1.add("你是唯一");
              // list1.add(34);  // 报错
              System.out.println("删除前:" + list1);
      
              // 删除元素
              list1.remove("JavaSE");
              System.out.println("删除后:" + list1);
      
              System.out.println("--------------------------------");
      
              MyArrayList<Double> list2 = new MyArrayList<>();
              list2.add(45.3);
              list2.add(99.0);
              list2.add(1034.54);
              System.out.println("删除前:" + list2);
      
              list2.remove(45.3);
              System.out.println("删除后:" + list2);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      删除前:[JavaSE, JavaSE, 我的集合, 我的集合, 你是唯一]
      删除后:[JavaSE, 我的集合, 我的集合, 你是唯一]
      --------------------------------
      删除前:[45.3, 99.0, 1034.54]
      删除后:[99.0, 1034.54]
      
      Process finished with exit code 0
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7


    5、原理

    • 把出现泛型变量的地方全部替换成传输的真实数据类型。
      在这里插入图片描述



    总结

    1、泛型类的核心思想是什么?

    • 把出现泛型变量的地方全部替换成传输的真实数据类型

    2、泛型类的作用是什么?

    • 编译阶段约定操作的数据的类型,类似于泛型在集合中的作用



    三、自定义泛型方法

    1、概述

    • 定义方法的同时定义了泛型的方法,就是泛型方法。

    2、格式

    修饰符 <泛型变量> 方法返回值 方法名(形参列表){
        
    }
    
    • 1
    • 2
    • 3
    • 范例:
    public <T> void show(T t){
        
    }
    
    • 1
    • 2
    • 3

    3、作用

    • 方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性。

    4、案例导学

    • 给你任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能!

      package com.app.d9_genericity_method;
      
      import java.util.Arrays;
      
      /**
          目标:通过案例导学,学会定义泛型方法来实现想要的功能
          需求:给你任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能
       */
      public class Test {
          public static void main(String[] args) {
              // 1、定义两个不同类型的数组,随便传入两组数据
              String[] names = {"赵敏", "小昭", "周芷若"};
              Double[] scores = {99.0, 59.9, 69.5, 100.0};
              printArrays(names);
              printArrays(scores);
      
              Integer[] arrTest1 = {};
              Integer[] arrTest2 = null;
              printArrays(arrTest1);
              printArrays(arrTest2);
          }
      
          /**
           * 2、定义泛型方法:printArrays,打印数组内容
           * @param arr       接收要打印的数组
           * @param        任意类型的数组
           */
          public static <T> void printArrays(T[] arr){
              if (arr != null) {
                  // 不为null
                  StringBuilder sb = new StringBuilder("[");
                  for (int i = 0; i < arr.length; i++) {
                      sb.append(arr[i]).append(i == arr.length-1 ? "" : ", ");
                  }
                  sb.append("]");
                  System.out.println(sb);
              }else {
                  System.out.println(arr);    // 为null,输出空数组变量
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      [赵敏, 小昭, 周芷若]
      [99.0, 59.9, 69.5, 100.0]
      []
      null
      
      Process finished with exit code 0
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6


    5、原理

    • 把出现泛型变量的地方全部替换成传输的真实数据类型。

    在这里插入图片描述



    总结

    1、泛型方法的核心思想是什么?

    • 把出现泛型变量的地方全部替换成传输的真实数据类型

    2、泛型方法的作用是什么?

    • 方法中可以使用泛型接收一切实际类型的参数,方法更具备




    四、自定义泛型接口

    1、概述

    • 使用了泛型定义的接口,就是泛型接口。

    2、格式

    修饰符 interface 接口名<泛型变量>{
        
    }
    
    • 1
    • 2
    • 3
    • 范例:
    public interface Data<E> {
        
    }
    
    • 1
    • 2
    • 3

    3、作用

    • 泛型接口可以让实现类选择当前功能需要操作的数据类型。

    4、案例导学

    • 教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作。

    在这里插入图片描述


    在这里插入图片描述


    在这里插入图片描述


    在这里插入图片描述


    在这里插入图片描述




    5、原理

    • 实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。

      在这里插入图片描述


      在这里插入图片描述




    总结

    1、泛型接口的作用是什么?

    • 泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作






    五、泛型通配符、上下限

    1、通配符:?

    • ?:可以在 “使用泛型” 的时候代表一切类型。

    2、通配符:E、T、K、V

    • E、T、K、V:是在定义泛型的时候使用的。

    3、案例导学

    • 模拟开发一个极品飞车游戏,所有的汽车都能一起参与比赛。
    • 注意:虽然BMW和BENZ都继承了Car,但是ArrayList< BMW>和ArrayList< BENZ>与ArrayList< Car>之间半毛钱关系都没有!!

    在这里插入图片描述


    在这里插入图片描述


    在这里插入图片描述


    • 泛型的上下限:

      • ? extends Car:? 必须是Car或者其子类(泛型上限)。

      • ? super Car:? 必须是Car或者其父类(泛型下限)。

      在这里插入图片描述




  • 相关阅读:
    java基于微信小程序的捷邻商品销售小程序+ssm+uinapp+Mysql+计算机毕业设计
    [C++数据结构](33)图,图的遍历,最小生成树,最短路径算法详解
    Python 面向对象编程:类、对象、初始化和方法详解
    C++设计模式之——桥接模式详解和代码实例
    垃圾收集器
    项目设计:YOLOv5目标检测+机构光相机(intel d455和d435i)测距
    wps及word通配匹配与正则匹配之异同
    Android 接口的default 方法运行时报错AbstractMethodError
    js模块 - amd cmd commonjs esm umd
    Vue2 为什么只能有一个根节点而vue3 可以多个
  • 原文地址:https://blog.csdn.net/yelitoudu/article/details/126236592