• 泛型的小结


    什么是泛型

    从JDK1.5开始引入泛型(generic)语法。对类型实现了参数化编辑器根据上下文推导出实参类型,省略了实参类型的填写。

    泛型的相关概念

    术语准备

    术语范例说明
    参数化的类型List表示List中元素的类型为String的容器
    实际类型参数String泛型使用时的实参
    泛型List声明中具有一个或者多个类型参数的类或接口即泛型
    形式类型参数E泛型声明中的形参
    原生态类型ListRaw Type。即没有使用泛型,主要是为了兼容之前大量没有使用泛型的代码。
    有限制类型参数只接受 Number 的子类型或者 Number 本身作为 E 的类型实参。 范围上界
    递归类型限制>只接收实现了Comparable接口的。范围上界
    有限制通配符类型List只接受Number 或其子类类型。范围上界
    无限制通配符类型List可以接收任意类型
    类型令牌String.class类的字面用在方法传递时的称呼
    泛型方法static List aslist(E[] a)

    泛型的编译时进行泛型擦除

    在这里插入图片描述

    程序编写的时候可以指定了泛型的元素类型为String类型,在编译的时候就变成Object。

    擦除机制,在编译的过程中,将泛型转换(所有类型)为Object的机制。

    泛型的作用

    • 加强类型安全检查:存放元素时,指明容器接收的对象的类型,让编译器进行类型安全检查
    • 无需手动进行类型转换,加快运行效率:取出元素时,无需手动进行类型转换,加快运行效率

    在这里插入图片描述

    进行类型安全检查之后,会在编译过程中反馈错误,减少运行时的错误。

    泛型的使用

    泛型常用的形参大写字母

    • E 表示 Element
    • K 表示 Key
    • V 表示 Value
    • N 表示 Number
    • T 表示 Type
    • S, U, V - 第二、第三、第四个类型

    泛型类语法

    class 类名称 <泛型标识、泛型标识,...> {
        private 泛型标识 变量名;
        ......
    }
    
    • 1
    • 2
    • 3
    • 4

    泛型接口语法

    interface 接口名称 <泛型标识,泛型标识,...>{
            泛型标识 方法名();
    }      
    
    • 1
    • 2
    • 3

    泛型方法语法

    方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表){
    
    }
    
    • 1
    • 2
    • 3

    泛型类的简单示例

    // 定义泛型类
    public class GenericClass<T, N> {
        private T value1;
        private N value2;
    
        // 使用泛型类型作为形参类型和返回值
        public T getValue1() {
            return value1;
        }
    
        public void setValue1(T value1) {
            this.value1 = value1;
        }
    
        public N getValue2() {
            return value2;
        }
    
        public void setValue2(N value2) {
            this.value2 = value2;
        }
    
        public static void main(String[] args) {
            GenericClass<Integer, String> s1 = new GenericClass<>();
            s1.setValue1(1);
            s1.setValue2("XX");
            System.out.println(s1.getValue1() + ":" + s1.getValue2());
            GenericClass<Double, String> s2 = new GenericClass<>();
            s2.setValue1(1.1);
            s2.setValue2("YY");
            System.out.println(s2.getValue1() + ":" + s2.getValue2());
        }
    }
    
    • 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

    泛型接口的简单示例

    在接口中定义的类型参数可以在接口中当做类型使用,任何需要类型的地方都可以使用类型参数替代

    // 定义泛型接口的类型参数为T
    public interface Humans<T> {
        // 使用类型参数T作为方法参数类型
        void say(T t);
    	// 使用类型参数T作为返回值类型
        T get();
    }
    
    // 实现泛型接口的时候传入类型
    public class BlackHuman implements Humans<BlackHuman> {
        public final String name;
    
        public BlackHuman(String name) {
            this.name = name;
        }
    
        @Override
        public void say(BlackHuman yellowHuman) {
            System.out.println("我叫" + this.name + ",是黑种人");
        }
    
        @Override
        public BlackHuman get() {
            return this;
        }
    }
    
    public class Demo {
    
        public static void main(String[] args) {
            BlackHuman blackHuman = new BlackHuman("乔丹");
            blackHuman.say(blackHuman);
            System.out.println(blackHuman.get().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

    基于泛型的简单工厂方法

    public interface IService {
        String getServiceName();
    }
    
    • 1
    • 2
    • 3
    public class MyService1 implements IService {
        @Override
        public String getServiceName() {
            return "My Service1.";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public class MyService2 implements IService {
        @Override
        public String getServiceName() {
            return "My Service2.";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    package com.donny.demo;
    
    /**
     * @author 1792998761@qq.com
     * @description
     * @date 2023/10/8
     */
    public class ServiceFactory {
    
        private ServiceFactory() {
        }
    
        // 简单写法-通过额外参数表名服务
        public static IService getService(String key) {
            if ("MyService1".equals(key)) {
                return new MyService1();
            } else if ("MyService2".equals(key)) {
                return new MyService2();
            } else {
                return null;
            }
        }
    
        // 使用泛型方法
        public static <T> T getInstance(Class<T> className) {
            T result = null;
            try {
                result = className.newInstance();
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
            return result;
        }
    }
    
    • 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
    public class Demo {
    
        public static void main(String[] args) {
            IService service1 = ServiceFactory.getInstance(MyService1.class);
            IService service2 = ServiceFactory.getInstance(MyService2.class);
            System.out.println(service1.getServiceName());
            System.out.println(service2.getServiceName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    泛型的上界与下界

    由于java中继承的特性

    上界语法

    class 类名称 <类型标识 extends 类型边界> {
        ......
    }
    
    • 1
    • 2
    • 3

    类型边界可以是类,也可以是接口。若类型边界是类,那么泛型中的类型只能接受边界类本身或其子类。若类型边界是接口,那么泛型中的类型必须实现了边界接口

    // 传入的类型需要是Number或Number的子类
    public interface Price<? extends Number> {
    }
    
    // 传入的类型需要实现Comparable接口
    public class ApplicableTransition<? extends Comparable<E>> {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    下界语法

    class 类名称 <类型标识 super 类型边界> {
        ......
    }
    
    • 1
    • 2
    • 3

    类型边界可以是类,也可以是接口。若类型边界是类,那么泛型中的类型只能接受边界类本身或其父类

    泛型的一些使用建议

    1. 不使用原生态类型

    2. 消除非受检警告

      可以在类,方法,对象声明上增加注解来消除非受检个告警

      @SuppressWarnings("unchecked")
      
      • 1
    3. 使用泛型时,列表优先于数组

    4. 利用有限通配符提升api的灵活性

    5. 优先考虑类型安全的异构容器

  • 相关阅读:
    性能 10 年提升 1000 倍,Zilliz 重磅发布 Milvus 2.4,开启 GPU 加速向量数据库新纪元!
    SpringBoot-配置
    1 动态规划
    想不到吧,Seata分布式事务也会出现ABA问题
    Ubuntu websocket程序
    速览默默发展的Web3邮箱赛道
    2023辽宁省数学建模B题数据驱动的水下导航适配区分类预测完整原创论文分享(python求解)
    零代码编程:用ChatGPT批量转换多个视频文件夹到音频并自动移动文件夹
    集合:(ArrayList)的插值和去重,包含(Iterator和listIterator)迭代器相关使用
    JAVA学习(5)-全网最详细~
  • 原文地址:https://blog.csdn.net/weixin_43820556/article/details/133687385