• 【JavaSE】泛型通关教程


    💁 个人主页:黄小黄的博客主页
    ❤️ 支持我:👍 点赞 🌷 收藏 🤘关注
    🎏 格言:All miracles start from sometime somewhere, make it right now.
    本文来自专栏:JavaSE从入门到精通
    在这里插入图片描述


    1 泛型引入

     我们来引入一个需求,在ArrayList集合中添加三个Dog对象,并遍历该集合,输出Dog对象的姓名。这点我们很容易做到,只需要在遍历的时候将Object对象向下转型为Dog就可以正常遍历了。但是,假如程序员在添加Dog对象时不小心添加了一只猫呢? 来看下面的代码:

    import java.util.ArrayList;
    
    /**
     * @author 兴趣使然黄小黄
     * @version 1.0
     */
    public class Generic0 {
        public static void main(String[] args) {
            ArrayList arrayList = new ArrayList();
            Dog dog1 = new Dog("小黄");
            Dog dog2 = new Dog("小花");
            Cat cat = new Cat("猫猫");
    
            arrayList.add(dog1);
            arrayList.add(dog2);
            arrayList.add(cat);  // 不小心添加了一只猫
    
            // 遍历
            for (Object o :
                    arrayList) {
                // 向下转型
                Dog dog = (Dog) o;
                System.out.println(dog.name);
            }
        }
    }
    class Dog{
        public String name;
    
        public Dog(String name) {
            this.name = name;
        }
    }
    class Cat{
        public String name;
    
        public Cat(String name) {
            this.name = name;
        }
    }
    
    • 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

    在这里插入图片描述

    🐱 传统方法可能遇到的问题:

    1. 不能对加入到集合的ArrayList中的数据类型进行约束(不安全);
    2. 遍历的时候,需要进行类型转换,在数据量大的情况下,对效率有影响。

    而通过使用泛型,则可以很好的解决该类问题。
    在创建 ArrayList 的时候,通过下面的语句使用泛型,限制元素的类型:

    ArrayList<Dog> arrayList = new ArrayList<>();
    
    • 1

    则编译器就会对类型进行检查,避免了将Cat加入ArrayList的错误情况:
    在这里插入图片描述
    🐰 泛型的好处:

    1. 编译时,检查添加的元素类型,提高了安全性;
    2. 减少了类型转换的次数,提高了效率;
    3. 不再提示编译警告。

    2 泛型讲解

    2.1 泛型的介绍

    🐱 简介:

    • 泛型又称参数化类型,是jdk1.5出现的新特性,解决数据类型的安全性问题;
    • 在类声明或实例化时只要指定好具体的类型即可;
    • Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException 异常。同时,代码更加简洁、健壮;
    • 泛型的作用:在类声明时通过一个标识表示类中某个属性的类型,或者某个方法的返回值类型,或者参数类型。
    class Person<E>{
        E element;  // E 表示 element 的数据类型,该数据类型在定义 Person 对象的时候指定,即在,编译期间,就确定E的类型
        
        public Person(E element){  // E 也可以是参数类型
            this.element = element;
        }
        
        public E method(){  // 返回类型为E
            return element;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.2 泛型实例

    1.创建 3 个学生对象;
    2.放入HashSet中,元素为Student;
    3.通过遍历HashSet,将值放入到 HashMap 中,Key 为 String name(HashSet中的Student), Value 为学生对象;
    4.使用两种方式遍历,HashMap。

    import java.util.*;
    
    /**
     * @author 兴趣使然黄小黄
     * @version 1.0
     */
    public class Generic2 {
        public static void main(String[] args) {
            HashSet<Student> students = new HashSet<>();
            students.add(new Student("黄小黄", 20));
            students.add(new Student("祢豆子", 7));
            students.add(new Student("春卷儿", 19));
            HashMap<String, Student> hashMap = new HashMap<>();
            // 遍历 HashSet,并将值传入 HashMap
            Iterator<Student> studentIterator = students.iterator();
            while (studentIterator.hasNext()){
                Student s = studentIterator.next();
                hashMap.put(s.name, s);
            }
            // 遍历 HashMap
            System.out.println("=================== 方式一 ==================");
            Set<String> keySet = hashMap.keySet();
            for (String s :
                    keySet) {
                System.out.println(s + "--->" + hashMap.get(s));
            }
            System.out.println("=================== 方式二 ==================");
            Set<Map.Entry<String, Student>> entrySet = hashMap.entrySet();
            for (Map.Entry es :
                    entrySet) {
                System.out.println(es.getKey() + "--->" + es.getValue());
            }
        }
    }
    
    // 学生类
    class Student{
        public String name;
        public int age;
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    • 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

    在这里插入图片描述

    2.3 泛型使用细节

    1. 给泛型指定数据类型时,必须是引用类型,不能是基本数据类型;
      在这里插入图片描述
    2. 给泛型指定具体类型后,可以传入该类型或者其子类类型;
    3. 泛型的使用形式如下:
      在这里插入图片描述
    4. 如果不使用泛型,默认是使用 Object类型。

    3 自定义泛型类

    🆔 基本语法:

    class 类名<T, R...>{
    	...
    }
    
    • 1
    • 2
    • 3
    1. 普通成员可以使用泛型(属性方法);
    2. 使用泛型的数组,不能初始化, 因为数组在 new 时不能确定泛型的类型,无法确定开辟的空间;
    3. 静态方法中不能使用类的泛型, 因为静态是和类相关的,在类加载的时候,对象还没创建,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化;
    4. 泛型类的类型,是在创建对象时确定的;
    5. 如果在创建对象时没有指定类型,默认为Object。

    4 自定义泛型接口

    🆔 基本语法:

    interface 接口名<T, R...>{
    	...
    }
    
    • 1
    • 2
    • 3
    1. 接口中,静态成员也不能使用泛型;
    2. 泛型接口的类型,在继承接口或者实现接口的时候确定;
    3. 没有指定类型,依然为Object;
    4. 在 jdk8 中,可以在接口中使用默认方法,该方法可以使用泛型。

    5 自定义泛型方法

    🆔 基本语法:

    修饰符 <T, R...>返回类型 方法名(参数列表){
    	...
    }
    
    • 1
    • 2
    • 3
    1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中;

    2. 当泛型方法被调用时,类型就会确定;
      在这里插入图片描述

    3. public void f(E e){},修饰符后面没有 ,则 f 不是泛型方法,而是使用了泛型;

    4. 泛型方法,可以使用类声明的泛型,也可以使用自己声明的泛型。


    6 泛型的继承与通配

    1. 泛型不具有继承性;
      在这里插入图片描述
    2. :支持任意泛型类型;
    3. :支持A类以及A类的子类,规定了泛型的上限;
    4. :支持A类以及A类的父类,不限于直接父类,规定了泛型的下限。

    🐰 通配示例如下,具体见注释:

    import java.util.List;
    
    /**
     * @author 兴趣使然黄小黄
     * @version 1.0
     */
    public class Generic3 {
        
        //  任意泛型
        public static void printCollection01(List<?> c){
            for (Object object:
                 c) {
                System.out.println(object);
            }
        }
    
        //  A表示上限,可以接受A或者A的子类
        public static void printCollection02(List<? extends A> c){
            for (Object object:
                    c) {
                System.out.println(object);
            }
        }
    
        //  A表示下限,可以接受A以及A的父类
        public static void printCollection03(List<? super A> c){
            for (Object object:
                    c) {
                System.out.println(object);
            }
        }
    }
    
    class C{}
    class A extends C{}
    class B extends A{}
    
    • 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

    写在最后

    🌟以上便是本文的全部内容啦,后续内容将会持续免费更新,如果文章对你有所帮助,麻烦动动小手点个赞 + 关注,非常感谢 ❤️ ❤️ ❤️ !
    如果有问题,欢迎私信或者评论区!
    在这里插入图片描述

    共勉:“你间歇性的努力和蒙混过日子,都是对之前努力的清零。”
    在这里插入图片描述

  • 相关阅读:
    微信小程序 js中写一个px单位转rpx单位的函数
    通用表表达式查询
    spring boot项目中@注释
    如何制作传统节日网站(纯HTML代码)
    PaxCompiler语言的编译器
    计算机网络
    ServletConfig接口干什么
    八、MFC对话框
    Zotero(1)---文献管理软件Zotero安装教程
    现在啥软件都有开源,BI 呢?
  • 原文地址:https://blog.csdn.net/m0_60353039/article/details/126490127