• Java高级应用——泛型


    泛型

    泛型化的由来概念

    1. 强类型语言的需求:在早期的编程语言中,程序员需要在编写代码时指定变量的具体类型。这种静态类型检查的方式可以确保类型的一致性,但也带来了一些限制。在处理不同类型的数据时,需要为每个类型写不同的代码,这导致了重复劳动和代码冗余。
    2. 参数化类型的引入:为了解决上述问题,研究人员开始思考如何实现能够处理多种类型的通用代码。参数化类型的概念应运而生。参数化类型允许在定义数据结构、函数或类时使用类型参数,使得这些结构可以适用于多种类型。

    简介:

    1. 类型参数:

      • Java泛型使用类型参数(Type Parameters)来表示泛型类型。

      • 类型参数用尖括号(<>)括起来,放在类、接口、方法的名称后面。

      • 例如,List中的T就是一个类型参数。

    2. 泛型类:

      • 通过在类的定义中使用类型参数,可以创建泛型类。

      • 泛型类可以在实例化时指定具体的类型参数。

      • 例如,List就是一个泛型类,可以用List表示整数类型的列表,用List表示字符串类型的列表。

    3. 泛型接口:

      • 与泛型类类似,可以定义泛型接口。

      • 泛型接口可以在实现时指定具体的类型参数。

      • 例如,Comparable就是一个泛型接口,用于比较两个对象的大小。

    4. 泛型方法:

      • 除了类和接口,还可以定义泛型方法。

      • 泛型方法在方法声明中使用类型参数,可以在调用时根据实际情况推断或指定类型参数。

      • 例如, T getValue()就是一个泛型方法,返回类型和参数类型都可以是泛型。

    5. 通配符:

      • Java泛型还支持通配符(Wildcard)机制。

      • 通配符用?表示,表示未知类型。

      • 通配符可以用于方法参数、类型限定和泛型实例化等场景。

      • 例如,List表示一个未知类型的列表。

    6. 类型限定:

      • 可以对泛型进行类型限定,即指定泛型参数必须是某个类或接口的子类型。

      • 例如,表示泛型参数必须是Number类或其子类。

    7. 类型擦除:

      • Java的泛型是通过类型擦除(Type Erasure)实现的。

      • 在编译时,泛型的类型信息会被擦除,泛型类型参数会被替换为其边界类型或Object。

      • 这是为了保持与Java旧版本的兼容性。

    8. 泛型数组:

      • Java不允许直接创建泛型数组,因为数组是具体化的,而泛型是擦除的。

      • 可以使用通配符或类型转换来处理泛型数组相关的操作。

    9. 泛型的类型推断:

      • Java 7引入了菱形操作符(Diamond Operator),可以通过省略类型参数来进行类型推断。

      • 例如,List list = new ArrayList<>(),其中的<>可以省略。

    10. 泛型和继承:

      • 在泛型中,子类型和父类型之间的关系与非泛型的类型参数一样。

      • 例如,ListList的子类型。

    自定义泛型

    自定义泛型是Java中强大的特性之一,它允许在类、接口和方法中定义参数化类型。

    1. 类型参数声明:

      • 在自定义泛型中,您需要使用类型参数来表示参数化类型。
      • 类型参数可以是任何合法的标识符,通常使用大写字母作为类型参数的名称(例如:TEK等)。
      • 类型参数声明放置在类、接口或方法的名称后面,用尖括号(<>)括起来。
    2. 泛型类:

      • 泛型类允许在类的定义中使用类型参数,从而创建参数化类型。

      • 类型参数可以在实例化时指定具体的类型。

      • 泛型类的方法和成员变量可以使用类型参数来定义其类型。

      • 示例:

        public class MyGenericClass<T> {
            private T value;
        
            public void setValue(T value) {
                this.value = value;
            }
        
            public T getValue() {
                return value;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
    3. 泛型接口:

      • 泛型接口允许在接口的定义中使用类型参数,从而创建参数化类型。

      • 类型参数可以在实现时指定具体的类型。

      • 泛型接口的方法可以使用类型参数来定义其参数和返回类型。

      • 示例:

        public interface MyGenericInterface<T> {
            T performAction(T value);
        }
        
        • 1
        • 2
        • 3
    4. 泛型方法:

      • 泛型方法允许在方法声明中使用类型参数,从而创建参数化方法。

      • 类型参数可以在调用时根据实际情况推断或指定类型参数。

      • 泛型方法的类型参数声明在方法的修饰符和返回类型之间。

      • 示例:

        public class MyGenericClass {
            public <T> void myGenericMethod(T value) {
                // 泛型方法的实现
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
    5. 类型边界:

      • 您可以对泛型进行类型限定,即指定泛型参数必须是某个类或接口的子类型。

      • 使用关键字 extends 表示类型边界,后跟限定的类型。

      • 示例:

        public class MyGenericClass<T extends Number> {
            // 类型参数必须是Number类或其子类
        }
        
        • 1
        • 2
        • 3
    6. 通配符:

      • 通配符是一种用于表示未知类型的特殊类型参数。

      • 使用问号(?)表示通配符。

      • 通配符可以用于方法参数、类型限定和泛型实例化等场景。

      • 示例:

        public void processList(List<?> list) {
            // 使用通配符处理未知类型的列表
        }
        
        • 1
        • 2
        • 3
    7. 类型擦除:

      • Java的泛型是通过类型擦除(Type Erasure)实现的。

      • 在编译时,泛型的类型信息会被擦除,泛型类型参数会被替换为其边界类型或Object

      • 泛型在运行时是不可见的,称为类型擦除。

      • 示例:

        List<Integer> list = new ArrayList<>();
        
        • 1

        编译后的代码:

        List list = new ArrayList();
        
        • 1
    8. 泛型数组:

      • Java不允许直接创建泛型数组,因为数组是具体化的,而泛型是擦除的。
      • 可以使用通配符或类型转换来处理泛型数组相关的操作。

    注意事项

    说明

    在声明自定义泛型类之后,我们可以在类的内部(例如属性、方法、构造器)使用该类的泛型。这样可以在类的内部使用泛型参数来指定具体的类型。

    在创建自定义泛型类的对象时,可以指定泛型参数类型。一旦指定了类型参数,类内部所有使用泛型参数的地方都会被具体化为指定的类型。

    如果在创建自定义泛型类的对象时没有指定泛型参数类型,则泛型会被擦除,泛型对应的类型将按照Object处理,但并不等同于Object。

    根据经验,如果使用了泛型,就应该一直使用泛型。如果不使用泛型,就不应该在类的任何地方使用泛型。

    在泛型的指定中,必须使用引用类型,不能使用基本数据类型。必须使用包装类来替代基本数据类型。

    除了创建泛型类的对象之外,当子类继承泛型类或实现泛型接口时,也可以确定泛型结构中的泛型参数。

    如果在向泛型类提供子类时,子类也无法确定泛型的类型,则可以继续使用泛型参数。还可以在现有的父类泛型参数的基础上添加新的泛型参数。

    注意

    泛型类可以有多个参数,此时应将多个参数一起放在尖括号内,例如:

    从JDK 7.0 开始,可以简化泛型操作,例如:ArrayList flist = new ArrayList<>();

    如果泛型结构是接口或抽象类,则无法创建泛型类的对象。

    不能使用new E[]来创建泛型数组,但可以使用(E[])new Object[capacity],其中ArrayList源码中的声明为Object[] elementData,而不是泛型参数类型的数组。

    在类或接口上声明的泛型在本类或本接口中代表特定的类型,但不能在静态方法中使用类的泛型。

    异常类不能带有泛型。

    以上是关于自定义泛型的一些注意事项和约束。使用泛型时请遵循这些规则,以确保代码的正确性和一致性。

  • 相关阅读:
    关于DatagridviewComboBox控件的若干技术问题
    关于优化算法在线更新simulink参数时的一些注意事项
    Spring中事务的传播行为有哪些?
    android 5.1 BatteryManager深入分析
    docker基础01
    Docker实战:docker compose 搭建Sonar
    iRGD-PEG-SH 环肽iRGD聚乙二醇巯基 SH-PEG-iRGD iRGD-SH-PEG 的参数信息
    【Proteus仿真】4x4矩阵键盘中断方式扫描 +数码管显示
    函数式编程-Stream流
    振弦传感器和无线振弦采集仪在隧道安全监测的解决方案
  • 原文地址:https://blog.csdn.net/Zdethm/article/details/133323665